【问题标题】:What is the expected return of `useEffect` used for?`useEffect` 的预期回报是什么?
【发布时间】:2019-11-10 01:05:47
【问题描述】:

在 React documentation 对于钩子他们说:

“这还允许您使用本地处理乱序响应 效果内的变量"

useEffect(() => {
    let ignore = false;
    async function fetchProduct() {
      const response = await fetch('http://myapi/product/' + productId);
      const json = await response.json();
      if (!ignore) setProduct(json);
    }

    fetchProduct();
    return () => { ignore = true };
  }, [productId]);

Demo app

请通过解释帮助我更好地理解这一点:

  1. 为什么返回一个函数? return () => { ignore = true };
  2. 本例中忽略了什么?

谢谢!

【问题讨论】:

  • 忽略 API 响应。每当输入更改时,就会设置状态,因此 useEffect 会再次运行,从而调用新的 API 调用。为了忽略旧的 API 调用结果,useEffect 的返回函数将之前的 useEffect 局部变量设置为 false。这保证了唯一最后呈现的 useEffect( 以及随之触发的 API 调用) 及其结果被存储。
  • medium.com/hackernoon/…这篇文章中,你可以看到为什么return () => { ignore = true };简而言之,就是避免竞争条件。

标签: reactjs ecmascript-6 react-hooks


【解决方案1】:

为什么return是一个函数? return () => { ignore = true };

来自docs

为什么我们从效果中返回一个函数?这是效果的可选清理机制。每个效果都可能返回一个在它之后进行清理的函数。这让我们可以保持添加和删除订阅的逻辑彼此接近。它们是相同效果的一部分!

React 究竟何时清理效果? React 在组件卸载时执行清理。然而,正如我们之前所了解的,效果会为每次渲染运行,而不仅仅是一次。这就是为什么 React 还会在下次运行效果之前清理上一次渲染中的效果。我们将在下文讨论为什么这有助于避免错误以及如何选择退出这种行为,以防它在后面产生性能问题。

本例中忽略了什么?

最初在useEffect Hook ignore 设置为let ignore = false;。 当fetchProduct 函数执行时,它会检查ignore 是否为true 并相应地设置setProduct(json)。这意味着我们将state 称为product,并使用setProduct(json) 设置state 中的值。这个product in state 用于在页面上呈现详细信息。

注意:由于[productId] 作为第二个参数传递给useEffectfetchProduct 函数只会在productId 更改时执行。

optimizing performance by skipping effects

【讨论】:

    【解决方案2】:
    //all imports
    function mufunc(){
      useEffect(()=>{ 
        const a = addEventListner('mouse' , console.log('mouse moves') )  //it prints when 
                                                                          //mouse moves
        return ()=>{
          removeEventListner(a)  //whenever the component removes it will executes
        }
      } ,[])
    }
    

    【讨论】:

      【解决方案3】:

      我会在这里解释一下,因为我花了一段时间才理解上面的解释,所以我会尽量让其他人更简单。

      回答您的问题:
      1- 为什么返回一个函数? return () => { ignore = true };
      useEffect 提供了 return 函数的使用,该函数用于清理函数的目的,OK!,你什么时候需要清理? 如果你订阅了某个东西,你想取消订阅它例如,您应该在 useEffect 的“返回函数”中添加取消订阅逻辑,而不是将逻辑放在其他地方,这可能会导致竞争条件!

      2- 本例中忽略了什么?
      ignore 用作一个标志,告诉函数是否忽略 api 调用。什么时候用?当你有比赛条件时。

      [竞态条件示例 - 你可以忽略这部分你已经熟悉竞态条件] em> 比如你点击产品列表,当每一个产品被点击时你会更新这个产品信息的页面,如果你在产品中快速点击很多次,useEffect会随着product_id的变化而更新,并在某个时候单击 product1 [将为 product1 调用 api] 然后快速 product2 [将为 product2 调用 api 并检索数据 causing -> setProduct(product2data) ] 而 product1 的数据仍然刚刚到达 导致 -> setProduct(product1data) 。这样我们就点击了 product2 !但是 product1 数据出现在页面上!!。

      ignore有什么关系??
      [逻辑解释]
      ignore,亲爱的,告诉 setProduct 忽略旧数据,不设置它,这样我们只会设置最后点击的产品,即使旧数据稍后到达。
      [代码说明]
      1- 第一种情况:没有比赛,product1 被点击 -> ignore 为 false ,调用 api ,检索数据,if(!ignore ) -> 将设置 product1 数据,现在清理功能将设置 ignore 为 true ,恭喜!

      2-秒场景->竞态,product1被点击->ignore为false,调用api,[数据仍未到达],现在product2被点击忽略为false,调用api,数据到达,if(@ 987654329@ ) -> 将设置 product2 数据,清理功能将忽​​略设置为 true ,product1 函数数据已到达 -> if(!ignore ) -> 为 false OOOPS,不会设置 product1 数据“旧数据”。

      这样我们将始终拥有新数据。 CHEERRRRRRRRS :D

      【讨论】:

      • 我喜欢你作为一个刚刚经历了“啊哈”时刻的人激动地回答这个问题的方式
      【解决方案4】:

      我们使用一个名为 ignore 的布尔标志来让我们的数据获取逻辑了解组件的状态(已安装/已卸载)。如果组件确实已卸载,则该标志应设置为 true,从而防止设置最终异步解析数据获取后的组件状态。当组件被卸载时,调用“return”(useEffect 的第二部分)。但是在这种情况下,由于依赖 [query] 当查询发生变化时,我们的组件被重新渲染,所以 sideEffect 被重新初始化。在你的IDE上运行this code,然后在你的浏览器中打开Devtools,比如chrome,然后清除控制台,然后在输入react这个词的输入中,尽快添加char 2,然后立即删除char 2。检查控制台看看发生了什么。

      【讨论】:

      • 这回答了 OP 的第二个问题,也是我的。谢谢
      【解决方案5】:

      当组件被卸载时,返回(useEffect 的第二部分)被调用。但是在这种情况下,由于依赖 [query] 当查询发生变化时,我们的组件被重新渲染,所以 sideEffect 被重新初始化。 在你的IDE上运行this code,然后在你的浏览器中打开Devtools,比如chrome,然后清除控制台,然后在输入react的输入中,尽快添加字符2,然后立即删除字符2。检查控制台以查看发生了什么。

      【讨论】:

        猜你喜欢
        • 2016-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-20
        • 2016-11-12
        • 2014-11-24
        • 1970-01-01
        • 2021-12-24
        相关资源
        最近更新 更多