React 文档再学习 7 使用 Effects 进行同步
2022-11-28 本文已影响0人
吴摩西
Effects 帮助开发者跟 React 外部沟通,例如同步状态给非 React 组件,跟服务器建立连接。或者当组件出现在页面时,发送一些日志。
在 React 组件中,包含两种代码:
- 渲染 (rendering) 代码,将 props 和 state 转换成 JSX。类似于数学公式,仅仅计算出结果,不做任何其他事情。
- 事件响应,事件响应不仅计算页面元素,也可能发送 HTTP POST 请求,或者跳转到其他页面。事件响应会因为特定的用户行为(例如点击按钮或者在 input 中输入)产生副作用 (side effect,修改程序状态)
Effect 可以让开发者在由于渲染本身触发,而不是用户特定行为触发的副作用。例如当一个聊天窗口出现在屏幕上时,连接到远端聊天服务器。Effect 会在渲染结束并且更新屏幕后执行。是跟外部系统(例如网络或者第三方组件库)同步的好时机。
不应该使用 useEffect 的地方
- Effect 不应当用于在 React 内部同步状态。
- 不应该在 props 改变时,在组件内部更新 state。
- 不要在 useEffect 中执行链式的数据计算或者状态更新。因为组件和它的子组件都会在计算时重新渲染。
- 不要在 effect 中初始化系统,会在 dev 模式下执行两次。
- 不要在 effect 中调用父组件响应函数,会引起多次渲染。
- 不要在 effect 中获取数据并更新父组件状态。在 react 中,状态变化都是自顶向下,在子组件中更新父组件,导致状态变化难以追踪,应当在父组件中获取数据并传递给子组件。
- 不要在 effect 中监听外部 store,react 中有专有的 hook
useSyncExternalStore
。 - 不要直接在 effect 中 fetch 数据,推荐使用第三方组件,如果自己执意获取数据。需要处理好两次加载的问题。
Effect 的生命周期
所有的 react 组件都有如下的生命周期
-
mount
,当组件出现在屏幕上。 -
update
,组件收到新的 props, state 时,进行更新。一般是由于用户的交互产生的。 -
unmount
,当组件从屏幕上移除。
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
// ...
}
一般可以理解成,当组件 mount 时,react 开始与外部系统同步,当组件 unmount 时,react 停止与外部系统同步。
如果不指定 dependency array,effect 会在每次 render 后执行。
去除多余的 dependency
function ChatRoom({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
const connection = createConnection();
connection.connect();
connection.on('message', (receivedMessage) => {
// 下面的代码会产生额外的 dependency
// setMessages([...messages, receivedMessage]);
setMessages(msgs => [...msgs, receivedMessage]);
});
return () => connection.disconnect();
}, [roomId]); // ✅ All dependencies declared
// ...