React useEffect和Vue watchEffect
前言
最近在学 react 的 useEffect,感觉用法、功能和 vue3 的 watchEffect 很类似,这里就对比下两者的区别。
说明
useEffect:
该 Hook 接收一个包含命令式、且可能有副作用代码的函数。 在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。 使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行。你可以把 effect 看作从 React 的纯函数式世界通往命令式世界的逃生通道。 默认情况下,effect 将在每轮渲染结束后执行,但你可以选择让它 在只有某些值改变的时候 才执行。 —— React 官网文档
watchEffect:
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。 ——Vue 官网文档
官网上两者的描述差别很大,useEffect 用于在函数组件中的副作用操作,组件每次渲染后执行。watchEffect 类似于 watch immediate,立即执行一个函数,依赖改变时重新执行。 两者官网上都提到副作用,副作用是函数式编程的一个概念。
所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
函数式编程纯函数只能进行数据计算,而副作用就是数据计算无关的操作。
使用
useEffect:
function Welcome(props) {
useEffect(() => {
document.title = `Hello, ${props.name}`;
}, [props.name]);
return <h1>Hello, {props.name}</h1>;
}
useEffect 第一个参数是一个函数,要执行的副作用函数,第二个参数是一个数组,指定副作用函数的依赖项,当依赖项发生变化时,副作用函数才会执行。如果第二个参数为空,副作用函数在组件初始渲染后执行一次,后面组件重新渲染就不会执行。
watchEffect:
const count = ref(0)
watchEffect(() => console.log(count.value),{})
// -> 输出 0
count.value++
// -> 输出 1
watchEffect 第一个参数也是要执行的副作用函数,watchEffect 会自动监听副作用函数中的依赖,不用指定副作用函数的依赖,第二个参数是一个可选的选项,可以用来调整副作用的刷新时机。 用法上 useEffect 和 watchEffect 类似,useEffect 的描述重点在执行副作用上,也有监听依赖的的功能。watchEffect 的描述重点在监听依赖上,也提到了执行副作用函数。
使用场景
React 中经常会使用 useEffect,使用场景一般是:
- React 与一些外部系统(网络、订阅、DOM) 同步的方法
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
- 获取数据
import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';
export default function Page() {
const [person, setPerson] = useState('Alice');
const [bio, setBio] = useState(null);
useEffect(() => {
let ignore = false;
setBio(null);
fetchBio(person).then(result => {
if (!ignore) {
setBio(result);
}
});
return () => {
ignore = true;
};
}, [person]);
- 监听依赖
function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId, serverUrl]);
}
- 输出日志
- 事件监听或订阅
由于 useEffect 在第一次渲染之后和每次更新之后都会执行并且依赖通过参数指定,依赖处理不当容易造成执行多次渲染,而且依赖过多非常容易造成循环依赖的问题,而且一旦出了问题,非常难排查很解决,因此不推荐用 useEffect 用于监听依赖,更多的用于其他副作用执行。
watchEffect 使用场景
- 监听依赖
const userID = ref(0)
watchEffect(() => console.log(userID))
- 防抖请求数据
watchEffect(() => {
// 异步api调用,返回一个操作对象
const apiCall = someAsyncMethod(props.userID)
onInvalidate(() => {
// 取消异步api的调用。
apiCall.cancel()
})
})
watchEffect 不用传参指定依赖,会自动地追踪其依赖,没有太大的使用负担,而且 watchEffect 默认是组件渲染之前执行执行的,执行多次对组件的渲染没有太大影响,watchEffect 更多使用在监听依赖上,而在纯函数的副作用操作上使用比较少。
useEffect 和 watchEffect 的作用很类似,但在具体使用上侧重点不一样。
转载自:https://juejin.cn/post/7213252345551749157