useEffect: 用于在组件渲染后执行一些操作,可以模拟 componentDidMount、componentDidUpdate 和 componentWillUnmount 生命周期
Copy const [ number , setNumber ] = useState ( 0 );
// 没有依赖
useEffect (() => {
console .count ( "useEffect" );
document .title = `You clicked ${ number } times` ;
} , );
// 正确
useEffect (() => {
console .count ( "useEffect" );
document .title = `You clicked ${ number } times` ;
} , [number]);
console .count ( "组件渲染!" );
Copy const [ state , setState ] = useState ({
name : "" ,
selected : false ,
});
// useMemo相当于vue的计算属性
const user = useMemo (
() => ({
name : state .name ,
selected : state .selected ,
}) ,
[ state .name , state .selected]
);
// 监听计算属性
useEffect (() => {
console .log ( `user改变, useEffect` );
} , [user]);
// 理解watch成直接监听state属性
useEffect (() => {
console .log ( `state改变, useEffect` );
} , [ state .name , state .selected]);
Copy const [ number , setNumber ] = useState ( 0 );
//没有一秒更新一次、没有清理定时器、
useEffect (() => {
console .log ( "useEffect" )
setInterval (() => {
setNumber (number + 1 );
} , [ 1000 ]);
} , [number]);
// 没有清除定时器,可能导致性能问题和内存泄漏问题
useEffect (() => {
console .log ( "useEffect" )
setInterval (() => {
setNumber ((prev) => prev + 1 );
} , [ 1000 ]);
} , []);
//正确用法,number一更新就会重新
useEffect (() => {
console .log ( "useEffect 开始!" );
const interval = setInterval (() => {
setNumber ((prev) => prev + 1 );
} , [ 1000 ]);
return () => { // 清理上一次useEffect
clearInterval (interval);
};
} , []);
console .count ( "组件渲染!" );
// 结果 组件渲染! -》 useEffect 开始!(只执行一次) -》组件渲染!-》组件渲染!
return < div >{number}</ div >;
Copy const [ toggle , setToggle ] = useState ( false );
useEffect (() => {
console .log ( "effect执行" );
return () => {
console .log ( "执行effect之前我先清除上一次的结果" );
};
} , [toggle]);
// 结果 执行effect之前我先清除上一次的结果-》effect执行
return (
< div >
< button onClick = {() => setToggle ( ! toggle)}>Toggle</ button >
</ div >
);
Copy const [ user , setUser ] = useState ({});
const id = useLocation (). pathname .split ( "/" )[ 2 ];
// 请求和清除,
useEffect (() => {
let unsubscribed = false ;
fetch ( `https://jsonplaceholder.typicode.com/users/ ${ id } ` )
.then ((res) => res .json ())
.then ((data) => {
if ( ! unsubscribed) {
setUser (data);
}
});
return () => {
console .log ( "cancelled!" )
unsubscribed = true ;
};
} , [id]);
//FETCH 和 ABORT
useEffect (() => {
const controller = new AbortController ();
const signal = controller .signal;
fetch ( `https://jsonplaceholder.typicode.com/users/ ${ id } ` , { signal })
.then ((res) => res .json ())
.then ((data) => {
setUser (data);
})
.catch ((err) => {
if (err === "AbortError" ) {
console .log ( "Request canceled!" );
} else {
// TODO:handle error
}
});
return () => {
controller .abort ();
};
} , [id]);
//Axios和取消请求
useEffect (() => {
const cancelToken = axios . CancelToken .source ();
axios
.get ( `https://jsonplaceholder.typicode.com/users/ ${ id } ` , {
cancelToken : cancelToken .token ,
})
.then ((res) => {
setUser ( res .data);
})
.catch ((err) => {
if ( axios .isCancel (err)) {
console .log ( "Request canceled!" );
} else {
//TODO:handle error
}
});
return () => {
cancelToken .cancel ();
};
} , [id]);
useEffect
vsuseLayoutEffect