外观
React 类组件的生命周期现在怎么答?
函数组件没有这套方法名,副作用在 useEffect 里。类组件要记住三条线:挂载、更新、卸载。数据请求放在挂载后,退订放在卸载,渲染函数本身保持纯净。
原理
挂载:constructor 初始化状态,render 描述 UI,然后提交 DOM,componentDidMount 里可以请求数据和订阅。
更新:新的 props 或 setState 之后再次 render,提交后进入 componentDidUpdate。在这里根据 props 变化发请求时,要比较前后 props,并在下一次更新或卸载时忽略过期结果。
卸载:componentWillUnmount 里取消订阅、定时器和未完成的请求。
getDerivedStateFromProps 和 getSnapshotBeforeUpdate 很少需要。前者容易把 props 抄进 state,造成两份数据。派生值直接在 render 里算。
曾经的 componentWillMount、componentWillReceiveProps、componentWillUpdate 在并发渲染下可能执行多次,不要再用。
追问
为什么请求不放在 constructor 或 render?
render 可能重复执行,必须是纯的。构造函数里发请求会在服务端渲染时产生副作用,也更难取消。挂载完成后,DOM 已经在,订阅也有了对称的卸载点。
和 Hooks 怎么对应?
useEffect 覆盖挂载后、更新后和卸载前的清理。useLayoutEffect 更接近提交后、绘制前的 componentDidMount 布局测量。见 React Hooks。
易错点
- 在
componentWillUnmount里setState。组件已经走了,这次更新没有意义,还会有警告。 componentDidUpdate里无条件setState,造成死循环。- 把
getDerivedStateFromProps当成「props 一变就同步进 state」的默认手段。