【问题标题】:Unnecessary rerenders with useContext使用 useContext 进行不必要的重新渲染
【发布时间】:2020-06-04 02:31:05
【问题描述】:

在这个example

function App() {
  const [value1, dispatch1] = useReducer(reducer, initialState1);
  const [value2, dispatch2] = useReducer(reducer, initialState2);

  return (
    <React.Fragment>
      <button
        onClick={() => {
          dispatch1({ type: "setFirstName", firstName: "nick" });
        }}
      >
        change1
      </button>
      <button
        onClick={() => {
          dispatch2({ type: "setFamilyName", familyName: "fname" });
        }}
      >
        change2
      </button>
      <JediContext1.Provider value={value1}>
        <Display1 />
      </JediContext1.Provider>
      <JediContext2.Provider value={value2}>
        <Display2 />
      </JediContext2.Provider>
    </React.Fragment>
  );
}

我使用来自here 的每个推荐的两个上下文。但是我可能误解了,也许github问题是指另一个案例? 因为它似乎不能解决我的问题。

上面代码的问题是如果我点击change1按钮,它会改变value1,组件Display2 也会重新渲染,甚至不会消耗 value1

实际上这对我来说很有意义,因为 我在 App 中更改了状态,因此它会重新渲染它的所有子级。 但是我不明白 github 链接中推荐的使用,因为它没有不在这里解决我的问题?

如果您有大型应用程序和根上下文提供程序,这可能会导致性能问题。

【问题讨论】:

  • 这是已知的事情,但由于未知原因,它已被讨论just recently。与钩子无关,仅与 Context API 的工作方式有关。希望很快有人会用例子来写出很好的答案。

标签: javascript reactjs react-hooks


【解决方案1】:

通常,并非总是如此,您希望记住您的 Providers 的 children 以避免这种情况。 在这种情况下,Display1Display2 可以是 PureComponent,或者只是

const Display1 = React.memo(() => <Whatever />)

您链接的 github 问题指的是另一个问题:您的提供商包含大量数据,而您只想订阅其中的一部分。在某些情况下,您可能会更新上下文的值,并且它将重新呈现未使用该值的使用者。在这种情况下,您可能只想在多个上下文中拆分它,如解释的那样。但这不是你的问题。

【讨论】:

  • 1) 一旦我更新了一个托管提供程序的组件,它就会导致它的所有子级重新呈现,所以我现在看不到 github 推荐适合的示例,如果你也可以详细说明的话我相信很多人会发现这很有用。 2)就我而言,您说“通常并非总是”-您的意思是有替代方案吗?
  • 抱歉,您能否说明需要更多详细信息/说明的内容?
【解决方案2】:

试试memoizing both components,这样它们只会在本地状态发生变化时呈现:

const MemoDisplay = React.memo(Display1);
const MemoDisplay2 = React.memo(Display2);

function App() {
  ...
  return (
    <React.Fragment>
      ...
      <JediContext1.Provider value={value1}>
        <MemoDisplay />
      </JediContext1.Provider>
      <JediContext2.Provider value={value2}>
        <MemoDisplay2 />
      </JediContext2.Provider>
    </React.Fragment>
  );
}

注意日志,之后没有不必要的渲染。

【讨论】:

    猜你喜欢
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    相关资源
    最近更新 更多