Open shuangmianxiaoQ opened 5 years ago
DOM
用JS对象的形式来表示的一棵DOM树,本质上就是JS对象
JS
Diff
标准的的Diff算法复杂度需要O(n^3),这显然不能满足性能要求,而React中使得算法复杂度降低到了O(n),主要是基于以下几点假设,也就是Diff策略:
O(n^3)
React
O(n)
Web UI
id
基于以上三个策略,React分别对Tree Diff,Component Diff,ElementDiff做了算法优化,事实也证明以上策略合理且准确的
Tree Diff
Component Diff
ElementDiff
VDOM
Dirty Component
Element Diff
key
getDerivedStateFromProps
componentWillReceiveProps
getSnapshotBeforeUpdate
componentWillUpdate
新版本React中,产生以上变动的原因也是跟Fiber架构有关,Fiber有reconciliation和commit两个阶段,对应的生命周期如下:
Fiber
reconciliation
commit
componentWillMount
shouldComponentUpdate
componentDidMount
componentDidUpdate
componentWillUnmount
在调度阶段进行了任务分隔,涉及到 暂停 和 重启 ,因此可能会导致调度阶段的生命周期函数在一次更新渲染中被多次调用,产生一些意外的错误
props
state
getDerivedStateFromProps(nextProps, prevState)
setState
getSnapshotBeforeUpdate(prevProps, prevState)
callback
高阶组件不是组件,而是一个增强函数,输入一个元组件,返回一个新的增强组件
// 将受控组件转为非受控组件 const WithChangeInput = Input => { return class extends Component { state = { value: "" }; handleChange = e => this.setState({ value: e.target.value }); render() { return ( <Input {...this.props} value={this.state.value} onChange={this.handleChange} /> ); } }; }; const Input = props => <input value="" {...props} />; const HOCInput = WithChangeInput(Input);
Redux Store
Reducer
<Provider>
store
context
connect
Redux
mapStateToProps
mapDispatchToProps
dispatch
action
在Action和Store之间,对dispatch的增强
Action
Store
redex-thunk
redux-saga
Generator
redux-persist
redux-logger
使用函数组件来代替类组件
useState
this.state
this.setState
const [count, setCount] = useState(0); <button onClick={() => setCount(count + 1)}>Click me</button>
useEffect(callback, [source]):可以看做是 componentDidMount、componentDidUpdate和componentWillUnmount的结合,第二个参数用于设置触发条件,仅当source改变时才会触发
useEffect(callback, [source])
source
useRef:获取组件真实节点
useRef
函数式编程是一种编程范式,常见的其他编程方式如命令式编程(面向过程),面向对象编程。
IO
Date
Math.random()
ramda
f(g(k(x))) -> compose(f, g, k)(x)
Immutable.js
虚拟 DOM 和 Diff 算法
虚拟
DOM
用
JS
对象的形式来表示的一棵DOM
树,本质上就是JS
对象Diff
算法标准的的
Diff
算法复杂度需要O(n^3)
,这显然不能满足性能要求,而React
中使得算法复杂度降低到了O(n)
,主要是基于以下几点假设,也就是Diff
策略:Web UI
中的DOM
节点跨层级移动的操作特别少,可忽略不计DOM
结构,不同的组件产生不同的DOM
结构id
进行区分基于以上三个策略,
React
分别对Tree Diff
,Component Diff
,ElementDiff
做了算法优化,事实也证明以上策略合理且准确的Tree Diff
:同层比较,如果发现同层节点有变化,则直接替换整个父节点及下面的子节点,而不是往下继续比较,这样一次遍历即可完成对整个VDOM
树的比较Component Diff
:如果是同一类型组件,则按照原策略继续比较VDOM
树;否则将该组件判断为Dirty Component
,从而直接替换下面的所有子节点。Element Diff
:对于列表节点提供唯一的key
属性可以帮助React
定位到正确的节点进行比较,从而大幅减少DOM
操作次数生命周期
getDerivedStateFromProps
代替componentWillReceiveProps
getSnapshotBeforeUpdate
代替componentWillUpdate
新版本
React
中,产生以上变动的原因也是跟Fiber
架构有关,Fiber
有reconciliation
和commit
两个阶段,对应的生命周期如下:reconciliation
(调度)componentWillMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
commit
componentDidMount
componentDidUpdate
componentWillUnmount
在调度阶段进行了任务分隔,涉及到 暂停 和 重启 ,因此可能会导致调度阶段的生命周期函数在一次更新渲染中被多次调用,产生一些意外的错误
componentDidMount
中添加事件监听,并在componentWillUnmount
中解绑事件componentDidMount
中进行数据的请求,而不是在componentWillMount
props
更新state
时,使用getDerivedStateFromProps(nextProps, prevState)
componentDidUpdate
中监听props
或者state
的变化componentDidUpdate
使用setState
时,必须加条件,否则进入死循环getSnapshotBeforeUpdate(prevProps, prevState)
在更新之前获取最新的渲染数据shouldComponentUpdate
中做条件渲染,优化渲染的性能setState
setState
后无法立即获取到更新后的值,可以在第二个参数callback
中获取最新值setState
更新时,会把所有状态合并后再进行更新(Object.assign),所以前面设置的key
会被后面的覆盖setState
第一个参数使用回调函数,可以避免批量更新的逻辑高阶组件
高阶组件不是组件,而是一个增强函数,输入一个元组件,返回一个新的增强组件
Redux
核心理念
Redux Store
中的数据无法直接修改Reducer
来修改状态,不要直接修改state
,而是返回一个新的state
工作流
React-Redux
<Provider>
:将store
通过context
传入组件connect
:高阶组件,方便在组件中使用Redux
mapStateToProps
:将store
通过props
传入mapDispatchToProps
:将dispatch
的action
通过props
传入Redux 中间件
在
Action
和Store
之间,对dispatch
的增强redex-thunk
:处理副作用,异步逻辑放在action
中处理redux-saga
:处理副作用,异步逻辑放在单独的文件中管理,适合复杂应用场景,使用Generator
函数编写redux-persist
:数据持久化redux-logger
:打印Redux
日志 ......React Hooks
使用函数组件来代替类组件
useState
:类似this.state
和this.setState
的替代useEffect(callback, [source])
:可以看做是componentDidMount
、componentDidUpdate
和componentWillUnmount
的结合,第二个参数用于设置触发条件,仅当source
改变时才会触发useRef
:获取组件真实节点函数式编程
函数式编程是一种编程范式,常见的其他编程方式如命令式编程(面向过程),面向对象编程。
理念
IO
操作,Date
对象,Math.random()
等ramda
库f(g(k(x))) -> compose(f, g, k)(x)
Immutable.js
库函数式编程的好处