
使用hooks有一段时间了,之前也针对自己的使用经验整理了一下 react hooks 实践总结,现在对最后那个 flag 也整理一下
首先说一下 react 的几个阶段
- 挂载
- constructor
- static getDerivedStateFromProps
- UNSAFE_componentWillMount 后期会被废弃
- render
- componentDidMount
- 更新
- static getDerivedStateFromProps
- UNSAFE_componentWillReceiveProps 后期会被废弃
- UNSAFE_componentWillUpdate 后期会被废弃
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
- 卸载
- componentWillUnmount
挂载
constructor
这个构造函数没法模拟
getDerivedStateFromProps
会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。 它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
// 这里注意到其实这个state并不是真实的state,而是一个跟props相关的对象
const useGetDeriveStateFromProps = (state, props, handle) => {
const cacheState = useRef(state);
const newState = handle(cacheState.current, props);
if (newState) {
cacheState.current = newState;
}
return cacheState.current;
};
// 使用
const Component = props => {
const state = useGetDeriveStateFromProps({ x: 1 }, props, (state, props) => {
console.log('new getDerivedStateFromProps')
if (props.add) {
state.x += 1;
return state;
}
return null;
});
return <div>{state.x}</div>;
};
UNSAFE_componentWillMount
在 render 之前执行,且执行一次
const useWillMount = handle => {
const isFirstLoad = useRef(true);
if (isFirstLoad.current) {
handle();
isFirstLoad.current = false;
}
};
componentDidMount
会在组件挂载后(插入 DOM 树中)立即调用,且整个生命周期中只会调用一次
const useDidMount = handle => {
useEffect(handle, []);
};
更新
getDerivedStateFromProps
上面已经说过了
UNSAFE_componentWillReceiveProps
当 props 改变的时候触发,且在 render 之前
const useWillReceiveProps = (props, handle) => {
const cacheProps = useRef(props);
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return;
}
if (cacheProps.current !== props) {
handle();
cacheProps.current = props;
}
};
UNSAFE_componentWillUpdate
当组件收到新的 props 或 state 时,会在渲染之前调用 UNSAFE_componentWillUpdate()。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。每次render前都会调用
const useWillUpdate = handle => {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return;
}
handle();
};
shouldComponentUpdate
根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。 这里可以用 React.memo 去优化函数组件的,且useState是会进行浅比较state\
getSnapshotBeforeUpdate
在最近一次渲染输出(提交到 DOM 节点)之前调用。 它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。 此生命周期的任何返回值将作为参数传递给 componentDidUpdate
这里有点难解决,可以考虑讲整个生命周期抽象出来
componentDidUpdate
会在更新后会被立即调用。首次渲染不会执行此方法。
// 注意这里漏掉了 snapshot,也就是 getSnapshotBeforeUpdate 的返回值
const useDidUpdate = (props, states, handle) => {
const isFirst = useRef(true);
const cacheHandle = useRef(handle);
const cache = useRef({ props, states });
cacheHandle.current = handle;
useEffect(() => {
if (isFirst.current) {
isFirst.current = false;
return;
}
cacheHandle.current(cache.props, cache.state);
cache.current = { props, states };
});
};
卸载
componentWillUnmount
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
const useWillUnmount = handle => {
const _handle = useRef();
_handle.current = handle;
useEffect(() => _handle.current, []);
};
setState 模拟
const useSetState = (state) => {
const [data, setData] = useState(state);
const setState = (newState) => setData((state) => ({ ...state, ...newState}))
return [data, setState];
}