1. 生命周期应对到hook
-
Constructor: 函数组件中使用useState来初始化state
-
componentDidMount, componentDidUpdate, componentWillUnmount: useEffect是综合这三个生命周期,一定要在后面写上effect里的依赖的属性
有关useEffect的FAQ文章:overreacted.io/zh-hans/a-c…
-
只在更新时使用effect,这个场景下可以借助一个ref来作为flag表明是首次渲染还是后续渲染,如果在一个项目中应用很多次,可以将它封装成一个hook useMemo 个人感觉同VUE的computed,他会记忆计算,也就是对结果生成缓存,它是在渲染期间运行。
2. 父子组件通信
- props 单向数据流转发
- refs转发,比如在一个组件中使用ref,可以使用React.forwardRef来获取传递给它的ref,hoc同理,
- contextAPI 结合redux ,通过value去传递,包含在Provider里的组件都可访问value里的属性,hook有useContext,相当于之前contextAPI的consumer,组件仍然需要Context.Provider来包裹,value来传递值
3. 我应该把函数当做effect的依赖吗?
一般建议把不依赖props和state的函数提到你的组件外面,并且把那些仅被effect使用的函数放到effect里面。如果这样做了以后,你的effect还是需要用到组件内的函数(包括通过props传进来的函数),可以在定义它们的地方用useCallback包一层。为什么要这样做呢?因为这些函数可以访问到props和state,因此它们会参与到数据流中。
4. useEffect无限重复请求的问题
在vue中如果我们把发送请求的函数写在updated中,而且在这个函数中你还把返回值绑定到了dom上,那么你就发现一直在发送请求,因为dom结构改变就会出发update这个钩子函数,同理在react也一样
这个通常发生于你在effect里做数据请求并且没有设置effect依赖参数的情况。没有设置依赖,effect会在每次渲染后执行一次,然后在effect中更新了状态引起渲染并再次触发effect。无限循环的发生也可能是因为你设置的依赖总是会改变。你可以通过一个一个移除的方式排查出哪个依赖导致了问题。但是,移除你使用的依赖(或者盲目地使用[])通常是一种错误的解决方式。你应该做的是解决问题的根源。举个例子,函数可能会导致这个问题,你可以把它们放到effect里,或者提到组件外面,或者用useCallback包一层。useMemo 可以做类似的事情以避免重复生成对象。
5. 为什么可以用dispatch来替换依赖的props、state属性值
在使用useEffect的时候,我们需要添加依赖,如果我们忘记或者没有诚实地告诉effect我们使用的依赖,那么effect可能会不按照我们预想的去工作。比如我们设计一个时钟,我们用到了一个属性step,我们告诉effect我们依赖这个step
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
useEffect(() => {
const id = setInterval(() => {
setCount(c => c + step);
}, 1000);
return () => clearInterval(id);
}, [step]);
return (
<>
<h1>{count}</h1>
<input value={step} onChange={e => setStep(Number(e.target.value))} />
</>
);
然后每次step改变都会重启定时器,如果我们不想重新启动,我们可以借助dispatch,
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
useEffect(() => {
const id = setInterval(() => {
dispatch({ type: 'tick' }); // Instead of setCount(c => c + step);
}, 1000);
return () => clearInterval(id);
}, [dispatch]);
这两段代码看上去没啥不同,但是有一个点就是:是React会保证dispatch在组件的声明周期内保持不变。所以上面例子中不再需要重新订阅定时器
所以,(你可以从依赖中去除dispatch, setState, 和useRef包裹的值因为React会确保它们是静态的。不过你设置了它们作为依赖也没什么问题。)