useEffect的那些坑,你知道多少
引言
我发现很多前端工程师们在处理一些计算合并、事件流转的过程中,喜欢用 useEffect
来处理各类问题。
例如:
import { useRequest } from 'ahooks';
import React, { useEffect, useState } from 'react';
export function comp1({ setParams }) {
return <div onClick={() => setParams({ a: 1 })}>comp1</div>;
}
export function comp2({ defaultParams }) {
const { run } = useRequest(async () => {});
// 利用 defaultParams 的变化,运行某个事件
useEffect(() => run(), [defaultParams]);
return <div>comp2</div>;
}
export function Page() {
const [defaultParams, setDefaultParams] = useState({});
return (
<>
<comp1 setParams={setDefaultParams} />
<comp2 defaultParams={defaultParams} />
</>
);
}
import React, { useEffect, useState } from 'react';
export function Page({ defaultParams }) {
const [params, setParams] = useState(defaultParams);
useEffect(() => {
setParams({ ...defaultParams, appid: 'appid' });
}, [defaultParams]);
return <>{JSON.stringify(params)}</>;
}
上面两个例子算是比较典型的例子,都是想要说:当 xxx 变化,然后执行 xxx。
这都是典型的错误使用了 useEffect
,因为对于useEffect
和 setState
的操作,对于 React 来说并不是同步执行的,React 对于 useEffect
的解释非常清楚,useEffect:
useEffect
、useState
这类方法都是有延时的执行,因为对于 React 来说,状态的变更可能还需要处理 VDom 的生成,Diff算法,状态合并等等。这些都需要借助异步的执行才更为高效。useEffect
更是需要等待渲染结束后才会执行。
虽然这可能只是几毫秒的事情,但是如果依赖这些来做事件传递,流程处理,就意味着会出现许多中间态,因为他们不是线性同步在运行。
如果给一句话就是,请不要依赖 React 的状态变化及渲染,来干扰数据变化
最后给下上述2个例子的正确解法:
跨组件事件通信
import { useEventEmitter, useRequest } from 'ahooks';
import React from 'react';
export function comp1({ event$ }) {
return <div onClick={() => event$.emit()}>comp1</div>;
}
export function comp2({ event$ }) {
const { run } = useRequest(async () => {});
event$.useSubscription(() => run());
return <div>comp2</div>;
}
export function Page() {
// 可以采用 Context 进行跨组件层级传递
const event$ = useEventEmitter();
return (
<>
<comp1 event$={event$} />
<comp2 event$={event$} />
</>
);
}
计算属性
import { useCreation } from 'ahooks';
import React from 'react';
export function Page({ defaultParams }) {
const params = useCreation(() => ({ ...defaultParams, append: 'append' }), [defaultParams]);
return <>{JSON.stringify(params)}</>;
}
转载自:https://juejin.cn/post/7199828364952338492