前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >早读《A Complete Guide to useEffect》

早读《A Complete Guide to useEffect》

作者头像
icepy
发布2019-12-18 11:40:42
7490
发布2019-12-18 11:40:42
举报
文章被收录于专栏:子曰五溪子曰五溪

https://overreacted.io/a-complete-guide-to-useeffect/

这篇文章 Dan 将让你最终领会使用 useEffect 的一切,由于提取精髓,因此略有删减。

由于 effect 在每次渲染后都会执行一次,因此你需要在第三个参数中放置数据的依赖关系。

我们来看一个例子:

代码语言:javascript
复制
function Counter() {
  const [count, setCount] = useState(0);

  function handleAlertClick() {
    setTimeout(() => {
      alert('You clicked on: ' + count);
    }, 3000);
  }

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

当 count 点击到 3,然后启动 handlerAlertClick ,并且在3秒内将 count 点击到5,3秒后定时器 alert 的 count 值是 3,原因其实很简单,我们的函数组件渲染时每次都会被调用,而这个定时器捕获的其实是当时状态下的值。

这种状况下,我们可以更好的理解 effect 是如何获取最新 count 的值的,我们来看另外一个例子:

代码语言:javascript
复制
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

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

并不是 count 的值在不变的 effect 中发生了改变,而是每一次渲染中 effect 都不相同。其实 effect 函数也是属于上述类似的事件处理函数,每次渲染都是不同的 effect 函数,并且每个 effect 函数捕获的都是当时状态下的 props 和 state 值。

我们需要理解 useEffect 并不完全等同于 componentDidMount,由于闭包的原因它获取的 props 和 state 都是旧值,如果你想获取最新的,你可以使用 ref,我们需要明白的是它的建立并不是来反应生命周期,而是实现状态的同步。

effect 提供的清理机制,本质上来说只是消除副作用,比如订阅的取消。我们可以从其中理解 effect 的执行顺序,上一次的 effect 会在重新渲染后被清除。因此这个清除的动作并不会捕获到最新的 props 或 state ,它只会读取到定了它那次渲染时的状态。

effect 的好处在于可以在此处理 React 之外的东西,比如 DOM 的操作等。

一般情况下建议是把不依赖 props 和 state 的函数放到组件外部,把那些仅被 effect 使用的函数放到 effect 内部。当然如果你使用到了组件内的函数(比如 props 传递进来的函数)都可以在定义的地方使用 useCallback 包一层。

我们需要保持对依赖项的关注,因为我们在某些情况下,没必要每次都去执行一下 effect ,这很不可取。如果某些函数仅在effect中调用,你可以把它们的定义移到effect中,在依赖项中处理好函数依赖的计算的值即可。

让我们来看另外一个例子:

代码语言:javascript
复制
function Article({ id }) {
  const [article, setArticle] = useState(null);

  useEffect(() => {
    let didCancel = false;

    async function fetchData() {
      const article = await API.fetchArticle(id);
      if (!didCancel) {
        setArticle(article);
      }
    }

    fetchData();

    return () => {
      didCancel = true;
    };
  }, [id]);

  // ...
}

一般异步的情况中会存在这种竞态的问题,最简单的方式是使用一个布尔值来跟踪它。

最后结论:

Hooks太新了所以大家都还在低水平地使用它,尤其是在一些教程示例中。但在实践中,社区很可能即将开始高水平地使用Hooks,因为好的API会有更好的动量和冲劲。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 子曰五溪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档