useEffect使用场景
1、数据获取:组件挂载时获取数据(空依赖数组)
useEffect(() => {
async function getData() {
const res = await fetch('http://example.cn');
const jsonRes = await res.json();
setList(jsonRes.data.channels);
}
getData();
}, []);
数据获取写法会导致首次渲染闪烁(先渲染undefined,再更新)
export const getUser = preload(() => fetch('/api/user').then(res=>res.json()))
//页面内
const data = use(getUser())
2、订阅:在组件中订阅外部数据源(如websocket链接)
useEffect(() => {
function onMessage(event) {
setMessage(event.data);
}
const socket = new WebSocket('wss://example.com/api/data');
socket.onmessage = onMessage;
// 清理订阅,防止内存泄漏
return () => {
socket.close();
};
}, []); // 同样,只在组件挂载时运行一次
3、手动更改DOM:在某些情况下(使用第三方库直接操作DOM时)
useEffect(() => {
const element = document.getElementById('some-element');
element.style.backgroundColor = 'blue';
}, []); // 只在组件挂载时运行一次
4、清理资源:组件卸载时,可能需要执行一些清理操作,取消订阅或清除定时器
useEffect(() => {
const intervalId = setInterval(() => {
// 执行一些操作...
}, 1000);
return () => clearInterval(intervalId); // 清理定时器
}, []); // 只在组件挂载时运行一次,并在卸载时清理
5、依赖项变化时的副作用
6、设置定时器
什么情况下,使用useEffect无效?
1、依赖项未更新
useEffect的依赖数组中没有正确包含所有需要的依赖项,那么当这些依赖项改变时,useEffect不会重新运行。
useEffect(() =>{
// 仅当count改变时才执行
},[count])
如果count依赖于另一个变量otherValue但没有包括在依赖数组中,那么当otherValue改变时,useEffect不会触发。
2、无限循环
在useEffect的回调函数中直接或间接地修改其依赖项,将导致无限循环的副作用调用。
useEffect(() =>{
setCount(count + 1)//将导致useEffect再次执行
},[count])
3、错误的清理函数
如果useEffect返回一个清理函数,但在某些情况下这个清理函数没有被正确调用,可能会导致副作用没有被正确清理。确保在组件卸载时清理资源。
useEffect(() =>{
return () => {
//清理逻辑
}
},[])//确保在组件卸载时清理
4、错误的依赖项数组
如果依赖项数组为空([]),那么useEffect仅在组件挂载后运行一次。如果执行逻辑需要在每次渲染后都运行,应该省略依赖项数组或包含所有必要的依赖项。
useEffect(() =>{
//每次渲染后都执行
})
5、条件渲染问题
如果useEffect被包裹在条件语句中,可能会导致在某些条件下不执行。确保useEffect总是处于正确的组件作用域内。
if(someCondition){
useEffect(()=>{
// 逻辑
},[dependency])
}
useLayoutEffect
React 的 useLayoutEffect 是一个在 DOM 更新后同步调用效果的 React Hook,它在组件的生命周期中处于 componentDidMount 和 componentDidUpdate 之间的阶段,但它会在浏览器绘制任何东西之前同步执行。
使用场景
- DOM操作:需要在页面渲染之前操作DOM(比如滚动条位置、修改样式、元素大小调整等)
- 测量和布局计算:测量DOM元素尺寸/位置(动态调整布局)
- 避免闪烁:同步修改DOM样式避免闪烁
useEffect 与useLayoutEffect的区别
执行时机不同
在commit阶段不同时机执行,
- useEffect在commit阶段结尾异步调用,
- useLayoutEffect/componentDidMount同步调用。