Javascript 如何在使用React上下文时避免意外渲染?

Javascript 如何在使用React上下文时避免意外渲染?,javascript,reactjs,react-native,react-navigation-v5,Javascript,Reactjs,React Native,React Navigation V5,我的提供者下有两个功能组件 SubApp1和SubApp2在这里,当我在SubApp1中增加计数器1时,SubApp2也在渲染,即使不需要重新渲染 当我在SubApp2中增加计数器2时,SubApp1也在渲染 我知道这种情况经常发生,但如何避免这种情况呢 App.js: import React, {useContext, useState, memo} from "react"; import "./styles.css"; export const MainContext = React

我的提供者下有两个功能组件

SubApp1
SubApp2
在这里,当我在
SubApp1
中增加计数器1时,
SubApp2
也在渲染,即使不需要重新渲染

当我在
SubApp2
中增加计数器2时,
SubApp1
也在渲染

我知道这种情况经常发生,但如何避免这种情况呢

App.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>
  );
}
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);
import React,{useContext,useState,memo}来自“React”;
导入“/styles.css”;
export const MainContext=React.createContext();
export const MainProvider=({children})=>{
const[counter1,setCounter1]=useState(0);
const[counter2,setCounter2]=useState(0);
返回(
{儿童}
);
}
导出常量子应用1=备注(()=>{
const{counter1,setCounter1}=useContext(MainContext);
console.log('计数器1:',计数器1);
返回(
{
设置计数器1(计数器1+1);
}}>
增加计数1
);
});
导出常量子应用2=备注(()=>{
const{counter2,setCounter2}=useContext(MainContext);
console.log('counter2:',counter2);
返回(
{
设置计数器2(计数器2+1);
}}>
增加计数2
);
});
导出默认函数App({navigation}){
log('App正在呈现…');
返回(
{
导航。导航(“子应用1”);
}}>
导航到子应用程序1
{
导航。导航('SubApp2');
}}>
导航到子应用2
);
}
index.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>
  );
}
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);
从“React”导入React;
从“react dom”导入react dom;
从“/App”导入应用程序,{MainProvider};
常量MainApp=()=>(
);
const rootElement=document.getElementById(“根”);
render(,rootElement);

您应该将计数器作为道具传递给子应用程序。然后,memo会注意到只有更换道具的组件才会重新招标

大概是这样的:

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>
  );
}
export const Wrapper1=()=>{
const{counter1,setCounter1}=useContext(MainContext);
返回(
);
};
export const SubApp1=memo({counter1,setCounter1})=>{
console.log('计数器1:',计数器1);
返回(
{
设置计数器1(计数器1+1);
}}>
增加计数1
);
});
export const SubApp2=memo({counter2,setCounter2})=>{
console.log('counter2:',counter2);
返回(
{
设置计数器2(计数器2+1);
}}>
增加计数2
);
});
导出默认函数应用程序(){
const{counter2,setCounter2}=useContext(MainContext);
log('App正在呈现…');
返回(
);
}

Codesandbox链接不正确…

您应该将计数器作为道具传递给子应用程序。然后,memo会注意到只有更换道具的组件才会重新招标

大概是这样的:

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>
  );
}
export const Wrapper1=()=>{
const{counter1,setCounter1}=useContext(MainContext);
返回(
);
};
export const SubApp1=memo({counter1,setCounter1})=>{
console.log('计数器1:',计数器1);
返回(
{
设置计数器1(计数器1+1);
}}>
增加计数1
);
});
export const SubApp2=memo({counter2,setCounter2})=>{
console.log('counter2:',counter2);
返回(
{
设置计数器2(计数器2+1);
}}>
增加计数2
);
});
导出默认函数应用程序(){
const{counter2,setCounter2}=useContext(MainContext);
log('App正在呈现…');
返回(
);
}

Codesandbox链接不正确…

我遵循Peter Ambruzs的提示,但如果我将counter1作为参数传递,我会遇到问题。组件继续重新招标

但是,如果我只通过setCounter1函数,它就可以正常工作

下面是我使用typescript的示例

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

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

export default Campaigns;

const活动=():JSX.Element=>{
const{setAlert}=useContext(AlertContext);
返回;
};
const InnerCampaign=备忘录(
({setAlert}:any):JSX.Element=>{…},)
导出默认活动;

我遵循Peter Ambruzs的提示,但如果我将计数器1作为参数传递,我会遇到问题。组件继续重新招标

但是,如果我只通过setCounter1函数,它就可以正常工作

下面是我使用typescript的示例

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

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

export default Campaigns;

const活动=():JSX.Element=>{
const{setAlert}=useContext(AlertContext);
返回;
};
const InnerCampaign=备忘录(
({setAlert}:any):JSX.Element=>{…},)
导出默认活动;

非常感谢,但有一个问题,我只是把我的问题简单化了。在主代码中,实际上我使用的是导航,例如,我通过导航从应用程序转到
SubApp1
SubApp2
,v4导航没有警告将
setCount
作为参数发送,但在react导航5中,他们不建议将函数作为参数发送。我还没有使用react导航。在处理上下文的瘦包装器组件中包装子应用程序怎么样。这样,只有轻量级包装才会重新呈现。Memo即使在它的父对象被重新呈现时也会阻止重新呈现。我不知道它怎么能把它放在包装器组件中。谢谢你,这对我很有帮助。是的,我删除了codesandbox链接,因为没有导航。非常感谢,但有一个问题,我只是简单地解决了我的问题。在主代码中,实际上我使用的是导航,例如,我通过导航从应用程序转到
SubApp1
SubApp2
,v4导航中没有将
setCount
作为参数发送的警告,但在react导航5中,它们不推荐我