常用的hock-useEffect

8 篇文章 0 订阅
1 篇文章 0 订阅

useEffect:

用途:

  • 获取数据
  • 事件监听或订阅
  • 监控/改变DOM
  • 设置定时器,输出日志
  • 该 Hook 接收一个包含命令式、且可能有副作用代码的函数。

定义语法使用:

该函数有两个参数,第一个是 异步函数,第二个是 监听的数据

useEffect (() => {
  // 这里是用来放,需要执行的异步函数
}, [‘这里面是,用来放,需要监听的数据’])

当 useEffect 的第二个 参数 [] 监听的数据发生变化,那么,就会执行第一个参数里边的,异步函数,并且对页面重新进行渲染。

第一个参数是一个函数,必传项。是组件要执行的副作用。可以看做componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。

useEffect(() => {
    console.log('执行副作用');   // 普通函数,执行副作用,可以实现componentDidMount、componentDidUpdate
    return () => {             // return函数, 组件销毁时清除副作用,可以实现componentWillUnmount
        console.log("清除副作用");
    };
}, [count]);
useEffect 的基本语法:(第二参数为 基本类型的时候)
1、当 不写 第二个参数的时候:
useEffect (() => {
  getUserList(); // 这是一个从后端获取用户列表的 函数
});
// 所有更新都执行这个函数

这时没useEffect不传递第二个参数会导致每次渲染都会运行useEffect。然后,当它运行时,它获取数据并更新状态。然后,一旦状态更新,组件将重新呈现,这将再次触发useEffect,如此就会反复调用接口,反复渲染,这就是问题所在。

2、当第二个参数 [ ] 为空的时候:
  const [data, setData] = useState({ hits: [] });

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        'https://hn.algolia.com/api/v1/search?query=redux',
      );

      setData(result.data);
    };

    fetchData();
  }, []);
// 第二个参数为空,那么就没有监听任何函数,所以只在挂载和卸载的时候dom 发生改变,才会执行。

这个时候就只在,挂载和卸载的时候执行。

3、第二个参数为某个变量
useEffect(()=>{
  console.log(count);
  getUserList(); // 获取用户列表的函数
}, [count]);
// 我下边绑定了一个按钮,当按钮点击的时候,count++。

当按钮点击,count 改变,那么就会触发 这个 useEffect ,执行 getUserList() 和 console.log 并且重新渲染视图。

4、useEffect 可以有返回值

useEffect 本质上是一个函数,既然是一个函数,那么就可以拥有一个返回值 return。

return函数, 组件销毁时清除副作用,可以实现componentWillUnmount。

return 函数,会在组件销毁前执行。

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); // 可以取消请阅
    };
  });

在组件销毁前,清除订阅。

进阶用法:(第二参数为引用类型)
1、当参数是一个数组的时候:
const [count, setCount] = useState(1);
const newArr = [4,5];
useEffect(() => {
    setTimeout(() => {
        setCount(count+1);
    }, 1000);
    console.log(`第二个参数: 数组, 第 ${count} 次执行`);
}, [newArr]);
// 打印log,无限循环
// 第二个参数: 数组, 第 1 次执行
// 第二个参数: 数组, 第 2 次执行
// 第二个参数: 数组, 第 3 次执行
// 第二个参数: 数组, 第 ... 次执行

原因:

useEffect依赖项arr发生变化,此处依赖数组执行浅层比较[...] === [...] 为false)useEffect重新执行,useEffect中回调函数改变state值,state值改变触发组件重新渲染,无限循环

解决办法:

使用 useRef, useRef 会在每次渲染的时候,返回同一个ref对象,返回的ref在组件的整个生命周期保持不变。

const [count, setCount] = useState(1);
const refArr = useRef([4, 5, 6]);
useEffect(() => {
    setCount(count+1);
    console.log(`第二个参数: 数组, 第 ${count} 次执行`);
}, [refArr.current]);
// 打印log,执行一次
// 第二个参数: 数组, 第 1 次执行
2、当参数为 function的时候(useCallback)
const [count, setCount] = useState(1);
const consoleFunction = () => {
    console.log('consoleFunction');
};
useEffect(() => {
    setTimeout(() => {
        setCount(count + 1);
    }, 1000);
    console.log(`第二个参数: 函数, 第 ${count} 次执行`);
}, [consoleFunction]);
// 打印log,无限循环
// 第二个参数: 函数, 第 1 次执行
// 第二个参数: 函数, 第 2 次执行
// 第二个参数: 函数, 第 3 次执行
// 第二个参数: 函数, 第 ... 次执行

原因:

第一次渲染后执行一次useEffect,useEffect中回调函数改变state值,state值改变触发组件重新渲染,useEffect依赖项consoleFunction函数发生变化,此处依赖函数执行浅层比较(每次渲染都重新创建一个新的函数 function(前) === function(后)为false)useEffect重新执行,useEffect中回调函数改变state值,state值改变触发组件重新渲染,无限循环。

解决办法:

使用 useCallback,它会返回该回调函数的 memorized 版本,该回调函数仅在某个依赖改变才会改变。

const [count, setCount] = useState(1);
const consoleFunction = useCallback(() => {
    console.log('consoleFunction');
}, []);
useEffect(() => {
    setCount(count + 1);
    console.log(`第二个参数: 函数, 第 ${count} 次执行`);
}, [consoleFunction]);
// 打印log,执行一次
// 第二个参数: 函数, 第 1 次执行
3、当参数是 对象的时候(useMemo)
const [count, setCount] = useState(1);
const obj = {name: 'zhangsan'};
useEffect(() => {
    setTimeout(() => {
        setCount(count + 1);
    }, 1000);
    console.log(`第二个参数: 对象, 第 ${count} 次执行`);
}, [obj]);
// 打印log,无限循环
// 第二个参数: 对象, 第 1 次执行
// 第二个参数: 对象, 第 2 次执行
// 第二个参数: 对象, 第 3 次执行
// 第二个参数: 对象, 第 ... 次执行

原因:

浅比较

解决办法:

使用useMemo,useMemo该回调函数仅在某个依赖项改变时才会更新。此处使用[]依赖,组件重新渲染后对象不再重新定义。

const [count, setCount] = useState(1);
const obj = useMemo(() => ({name: 'zhangsan'}), []);
useEffect(() => {
    setCount(count + 1);
    console.log(`第二个参数: 对象, 第 ${count} 次执行`);
}, [obj]);
// 打印log
// 第二个参数: 对象, 第 1 次执行
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值