为什么useEffect不会在每个渲染上触发?

时间:2019-04-01 09:04:45

标签: reactjs react-hooks mobx-react

我的组件有两个Rect.useEffect钩子

const Example = ({ user }) => {
  React.useEffect(() => {
    autorun(() => {
      console.log("inside autorun", user.count);
    });
  });

  // Only runs once
  React.useEffect(() => {
    console.log("Why not me?");
  });

  return <Observer>{() => <h1>{user.count}</h1>}</Observer>;
};

我使用mobx更新了此组件。它已正确重新渲染。但是"Why not me?"仅打印一次。

按照official docs

  

默认情况下,效果在每次完成渲染后运行

这意味着{console.log("Why not me?");也应在每次更新道具user时运行。但事实并非如此。控制台输出是这个

这种明显不一致的原因是什么?

我的完整代码可以在这里查看

Edit mobx-useEffect query

2 个答案:

答案 0 :(得分:3)

在Mobx中,就像提供渲染函数回调的Observer组件一样,autorun函数也独立于react生命周期执行。

之所以会发生这种现象,是因为您拥有用户数作为可观察变量

根据mobx反应文档

  

Observer是一个React组件,它将观察者应用于匿名   组件中的区域。一个孩子,一个没有争执的孩子   函数,该函数应该恰好返回一个React组件。的   该函数中的渲染将被跟踪并自动   在需要时重新渲染。

和mobx文档

  

使用autorun时,提供的功能将始终被触发   一次,一次,一次,一次   变化。

您可以通过直接在功能组件内部登录来确认此行为,并且您将观察到该组件仅渲染一次

编辑:

回答您的问题

  

如果我将useEffect更改为此

React.useEffect(autorun(() => {console.log("inside autorun", user.count)}));
     

基本上从useEffect中删除匿名函数,然后通过   直接运行,则仅运行一次。为什么会这样呢?那是什么   差异?

区别在于autorun返回一个disposer function,该autorun在运行时将处置disposer,并且不再执行。

来自文档:

  

自动运行的返回值是一个处理程序函数,可以是   用于在不再需要自动运行时进行处理。

现在发生的事情是,由于useEffect在运行时执行为其提供的回调,因此执行的回调是autorun返回的DECLARE @var_date char(10) SET @var_date = (SELECT CONVERT(DATE,GETDATE())) SELECT TOP(25) * FROM OPENQUERY (OPICS, 'SELECT CASE WHEN OPICS.FXDH.BR = 10 THEN ''Botswana'' WHEN OPICS.FXDH.BR = 20 THEN ''Mozanmbique'' WHEN OPICS.FXDH.BR = 30 THEN ''Rwanada'' WHEN OPICS.FXDH.BR = 40 THEN ''Tanzania'' WHEN OPICS.FXDH.BR = 50 THEN ''Zambia'' WHEN OPICS.FXDH.BR = 60 THEN ''Zimbabwe'' END AS COUNTRY, OPICS.FXDH.DEALNO, to_char (OPICS.FXDH.DEALDATE,''YYYY-MM-DD'') as Deal_Date, to_char (OPICS.FXDH.VDATE, ''YYYY-MM-DD'') as V_Date, OPICS.FXDH.PS, OPICS.FXDH.CCY, OPICS.FXDH.CCYAMT, OPICS.FXDH.CCYRATE_8, OPICS.FXDH.CTRCCY, to_char (OPICS.OPER.OPERNAME) as OPERNAME, to_char (OPICS.CUST.CFN1) as CFN1, to_char (OPICS.PROD.PDESC) as PDESC, to_char (OPICS.PORT.PORTDESC) as Report_Description FROM OPICS.FXDH FXDH INNER JOIN OPICS.OPER OPER ON (FXDH.BR = OPER.BR) AND (FXDH.TRAD = OPER.OPER) INNER JOIN OPICS.CUST CUST ON (FXDH.CUST = CUST.CNO) INNER JOIN OPICS.PROD PROD ON (FXDH.PRODCODE = PROD.PCODE) INNER JOIN OPICS.PORT PORT ON (FXDH.PORT = PORT.PORTFOLIO) AND (FXDH.BR = PORT.BR) WHERE OPICS.FXDH.DEALDATE = TO_DATE(''2018-08-29'', ''YYYY-MM-DD'') --dateString AND OPICS.FXDH.BR = 10 --ORDER BY OPICS.FXDH.DEALDATE DESC'); 函数,这实际上取消了您的自动运行。

答案 1 :(得分:1)

看来您的组件没有重新渲染。 autorun收到回调,并且可能独立于渲染调用。

Example组件仅在其父对象重新渲染或其道具发生更改时才重新渲染。

使用以下代码观察实际情况:

const Example = ({ user }) => {
  console.log('render');
  React.useEffect(() => {
    console.log('useEffect autorun');
    autorun(() => {
      console.log("inside autorun", user.count);
    });
  });

  // Only runs once
  React.useEffect(() => {
    console.log("Why not me?");
  });

  return <Observer>{() => <h1>{user.count}</h1>}</Observer>;
};