【问题标题】:Why react context provider component renders twice [duplicate]为什么反应上下文提供程序组件呈现两次[重复]
【发布时间】:2020-08-15 08:55:59
【问题描述】:

我在玩 React Context API,发现提供程序在每次值更改时呈现两次。

这就是我所做的。

  1. 创建了一个上下文,然后是一个呈现其提供者的组件。
  2. 提供程序提供状态值及其设置器。
  3. 创建了一个直接渲染其子级的直接子级。
  4. 创建了一个消费者,它读取上下文值并添加一个按钮来更改它。
  5. 每个组件在呈现时都会执行一个 console.log。
  6. 为提供程序添加了一个效果,无需在每次呈现时都记录日志。
  7. 在提供程序中添加了一个 ref,该 ref 在每次渲染时递增,并在渲染和效果中记录。

问题?

每次点击按钮更改上下文值时,提供程序渲染两次,但效果只执行一次。

所以 ref 总是递增两次,但效果每次只获取最后一个值(它跳过一个值!)。

此外,在提供程序的第一次渲染时,它会记录两次相同的 ref 值,这对我来说很奇怪。

谁能告诉我为什么会出现这种行为?

代码如下:

提供者:

const MyContext = React.createContext(0);

function Provider({ children }) {
  const state = React.useState("Yes");
  const ref = React.useRef(0);
  ref.current += 1;
  console.log("Context provider ", ref.current);
  React.useEffect(() => {
    console.log("effect on provider, ref value = ", ref.current);
  });

  return <MyContext.Provider value={state}>{children}</MyContext.Provider>;
}

两个孩子

function DirectChild({ children }) {
  console.log("provider direct child");
  return children;
}

function Consumer() {
  console.log("consumer");
  const [state, setState] = React.useContext(MyContext);
  return (
    <div>
      <span>State value: {state}</span>
      <br />
      <button onClick={() => setState(old => old + "Yes")}>Change</button>
    </div>
  );
}

应用程序

export default function App() {
  console.log("APP");
  return (
    <Provider>
      <DirectChild>
        <Consumer />
      </DirectChild>
    </Provider>
  );
}

这是codesandbox demo

【问题讨论】:

  • 将状态逻辑移到应用层,现在行为也在App,渲染两次,记录两次,只有一个效果,这里是a demo
  • 我的理解是 refs 用于引用 Dom 对象,而不是 state refs(即useState)。我想你可以用它们来引用任何东西,只是不确定这是他们的意图:"avoid using refs for anything that could be done declaratively".
  • 是的,refs 旨在创建一个可变对象,您可以随意改变它。我找到了这背后的原因,我现在会发布答案;在代码框里是 React.strictMode
  • 并且只影响开发模式
  • 是的,我怀疑是这样的:)我上周左右回答了一个类似的问题......

标签: javascript reactjs


【解决方案1】:

找到原因,

没有错误,也没有奇怪的行为,我只是错过了默认情况下在 React.StrictMode 父级中呈现应用程序的代码框。

首先,我将代码移植到本地项目,然后观察到没有问题。

搜索了codesandbox repo问题,发现它与严格模式下的反应行为有关:

预计 setState 更新程序将在开发中以严格模式运行两次。这有助于确保代码不依赖于它们一次运行(如果异步渲染被中止并重新启动,则不会出现这种情况)。如果您的 setState 更新程序是纯函数(它们应该是),那么这不应该影响您的应用程序的逻辑。

Codesandbox issue

React issue

但是,效果只执行一次,错过了我的参考更新。

【讨论】:

  • 如果你想跟踪 ref 值,你可以使用React.useCallback 这是示例` const ref = React.useRef(0);让 setRef = React.useCallback(setValue => { ref.current = setValue(ref.current); console.log(ref.current) }, []) React.useEffect(() => { setRef(old => old + 1) }, [状态[0]]);`
猜你喜欢
  • 1970-01-01
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多