使用React Context时避免重新渲染

时间:2020-06-04 19:09:32

标签: html reactjs typescript

Codesandbox here

我正在使用各种组件状态的上下文,在这种情况下,选中了该复选框,并正在使用该组件来改变该组件状态。但是,通过仅单击一个复选框,将重新渲染所有四个组件(复选框)。钩入上下文并更改上下文时,如何防止这种重新渲染?谢谢。

index.tsx:

import * as React from "react";
import ReactDOM from "react-dom";
import { ContextProvider, useMyContext } from "./context";
import "./styles.css";

const Checkbox: React.FC<{ id: number }> = ({ id }) => {
  React.useEffect(() => console.log(`Checkbox ${id} Render`));

  const { setValue, value } = useMyContext();

  return (
    <input
      onClick={() => setValue(id)}
      checked={id === value}
      type="checkbox"
    />
  );
};

const Container: React.FC = () => {
  React.useEffect(() => console.log("Container Render"));

  return (
    <div>
      {[0, 1, 2, 3].map(id => (
        <Checkbox id={id} />
      ))}
    </div>
  );
};

const App: React.FC = () => {
  return (
    <ContextProvider>
      <Container />
    </ContextProvider>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

context.tsx:

import * as React from "react";

interface ContextState {
  setValue: (id: number) => void;
  value: number;
}

const initialContextState: ContextState = {
  setValue: () => {},
  value: 0
};

const Context = React.createContext<ContextState>(initialContextState);

export const ContextProvider: React.FC = (props: object) => {
  const [value, setValue] = React.useState<number>(0);

  return (
    <Context.Provider
      value={{
        setValue,
        value
      }}
      {...props}
    />
  );
};

export const useMyContext = (): ContextState => React.useContext(Context);

2 个答案:

答案 0 :(得分:1)

您不能阻止重新渲染上下文消耗组件(在您的示例中为Checkbox)-更新上下文值时强制重新渲染只是Context API的工作方式,您不能应用任何对其具有“选择性”。

您可以 采取的措施是将消耗组件的实际内容中的昂贵部分提取出来,将其提取为用React.memo包裹的子组件(或内联为JSX块)包裹在useMemo钩子-docs中),从上下文中获取所需的值,并将这些作为道具传递给该子组件/依赖项到useMemo部分。

然后,内置备忘录将“正常工作”,并且不会为实际值未更新的复选框重新渲染子组件(昂贵的部分),因为相关的道具不会改变。

使用这样的备注可以解决您需要解决的任何实际性能问题,但仅提醒您,在90%的时间里,这些东西都没有关系。在以这种方式重构组件之前,测试并确定性能实际上是一个问题。通常,根本不值得使用额外的间接方法来解决非问题!

答案 1 :(得分:0)

Here 你可以找到一个类似的例子,

使用此库 react-hooks-in-callback 您可以过滤掉所有不必要的重新渲染

检查结果Here