#yyds干货盘点#react之useEffect
  Qp5JTyIxtbwu 2023年11月19日 17 0

React的Hooks API为我们提供了一种新的处理副作用的方式 ——useEffectuseEffect函数接受两个参数:一个是_副作用函数_和一个_依赖数组_。副作用函数是在组件render之后运行,而依赖数组告诉React何时应该执行或跳过该副作用。如果没有提供依赖数组,`useEffect`将在每次渲染后运行。如果提供了空的依赖数组,副作用将只在第一次渲染后及在卸载时运行。

jsx
useEffect(() => {
   console.log('component did mount');
   return () => {
     console.log('component will unmount');
   }
}, []);

实现原理

useEffect是如何完成这些工作的呢?核心在于React如何决定何时调用副作用函数。这涉及到React对组件生命周期的管理。React使用一个队列存储所有的state和side-effect,以保证他们的正确执行顺序。在每一个render周期,React都会迭代这个队列,并比较当前的依赖数组和上一次的依赖数组。如果有任何更改,React就会运行新的副作用函数。在运行新副作用函数前,React会首先调用先前副作用的cleanup函数。

假设我们有一个计数器应用。每当计数器的数值改变时,我们希望能够显示更新的数值。

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

在这个例子中,useEffect接收了一个副作用函数,该函数会更新文档的title为当前的计数器的数值。另一个参数[count]是一个依赖数组,告诉React仅当count变化时才应运行该效应。为实现这个功能,React内部维护了队列来跟踪stateside-effect。首次渲染(或count更新时),React会调用副作用函数,创建新的副作用并将其添加到队列中。由于这个副作用依赖于count,React还会将当前的count值与副作用一同存储。在下一次渲染时,如果count的值已经发生变化,React会比较新旧count值。由于这两者不同,React首先会清理旧的副作用,然后再调用新的副作用函数。这样就确保了每次count值改变时,useEffect都能正确地工作。这个例子应该能帮助您理解useEffect工作原理的主要部分:如何跟踪副作用,如何比较新旧依赖值,如何根据依赖值的变化决定是否执行副作用函数,以及如何清理旧的副作用。

手写简易版useEffect

那么如果要自己实现一个简易版的`useEffect`,应该怎么做呢?这需要保持`deps`的跟踪,再根据`deps`是否改变来决定是否调用`effect`。我们可以采用以下方式实现:

let _deps; // 全局存储依赖

function useEffect(callback, deps) {
  const hasNoDeps = !deps;
  const depsChanged = _deps ? 
      !deps.every((el, i) => el === _deps[i]) 
      : true;

  if (hasNoDeps || depsChanged) {
    callback();
    _deps = deps;
  }
}

这样,我们就实现了一个简易版的`useEffect`。这个版本的`useEffect`仅适用于理解`useEffect`的基本工作原理,它并没有实现如何处理cleanup函数,以及如何管理多个`useEffect`等更复杂的情况。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月19日 0

暂无评论

Qp5JTyIxtbwu