Как избежать неожиданного рендеринга при использовании React Context? - PullRequest
0 голосов
/ 16 февраля 2020

У меня есть два функциональных компонента под моим провайдером:

SubApp1 и SubApp2, и здесь, когда я увеличиваю значение счетчика 1 в SubApp1, SubApp2 также выполняет рендеринг, даже когда он не нужен быть перерисованным.

И когда я увеличиваю значение counter2 в SubApp2, SubApp1 также выполняет рендеринг.

Я знаю, что это происходит регулярно, но Как можно избежать этой ситуации?

Приложение. js:

import React, {useContext, useState, memo} from "react";
import "./styles.css";


export const MainContext = React.createContext();

export const MainProvider = ({children})=> {

  const [counter1, setCounter1] = useState(0);
  const [counter2, setCounter2] = useState(0);


  return (
    <MainContext.Provider value={{
      counter1, setCounter1,
      counter2, setCounter2,
    }}>
      {children}
    </MainContext.Provider>
  );
}

export const SubApp1 = memo(()=> {
  const {counter1, setCounter1} = useContext(MainContext);
  console.log('Counter 1: ', counter1);
  return (
    <div className="App">
          <button onClick={()=> {
            setCounter1(counter1+1);
          }}>
            Increase Count 1
          </button>
    </div>
  );
});

export const SubApp2 = memo(()=> {

  const {counter2, setCounter2} = useContext(MainContext);

  console.log('counter2: ', counter2);

  return (
    <div className="App">
          <button onClick={()=> {
            setCounter2(counter2+1);
          }}>
            Increase Count 2
          </button>
    </div>
  );
});


export default function App ({navigation}){


  console.log('App Is rendering...');



  return (
    <div className="App">

         <button onClick={()=> {
            navigation.navigate('SubApp1');
          }}>
            navigate to SubApp1
          </button>

          <button onClick={()=> {
            navigation.navigate('SubApp2');
          }}>
            navigate to SubApp2
          </button>

    </div>
  );
}

index. js:

import React from "react";
import ReactDOM from "react-dom";

import App, {MainProvider} from "./App";

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

Ответы [ 2 ]

2 голосов
/ 16 февраля 2020

Вы должны передать счетчик в SubApps в качестве реквизита. Тогда памятка позаботится о том, чтобы только компонент с измененными реквизитами был перерисован.

Примерно так:

export const Wrapper1 = ()=> {
  const {counter1, setCounter1} = useContext(MainContext);
  return (
    <SubApp1 {...{counter1, setCounter1}} />
  );
};

export const SubApp1 = memo(({counter1, setCounter1})=> {

  console.log('Counter 1: ', counter1);
  return (
    <div className="App">
          <button onClick={()=> {
            setCounter1(counter1+1);
          }}>
            Increase Count 1
          </button>
    </div>
  );
});

export const SubApp2 = memo(({counter2, setCounter2})=> {
  console.log('counter2: ', counter2);

  return (
    <div className="App">
          <button onClick={()=> {
            setCounter2(counter2+1);
          }}>
            Increase Count 2
          </button>
    </div>
  );
});


export default function App (){

  const {counter2, setCounter2} = useContext(MainContext);

  console.log('App Is rendering...');

  return (
    <div className="App">
        <Wrapper1/>
        <SubApp2 {...{counter2, setCounter2}} />
    </div>
  );
}

Ссылка Codesandbox неверна ...

0 голосов
/ 06 марта 2020

Я следую совету Питера Амбруза, но у меня проблема, если я передам counter1 в качестве параметра. Компонент продолжает рендеринг.

Но, если я передаю только функцию setCounter1, она отлично работает.

Ниже мой пример с использованием машинописи.

const Campaigns = (): JSX.Element => {
  const { setAlert } = useContext(AlertContext);
  return <InnerCampaign {...{ setAlert }} />;
};

const InnerCampaign = memo(
  ({ setAlert }: any): JSX.Element => {...},)

export default Campaigns;

...