使用 React Context 如何避免意外渲染?
How to avoid unexpected rendering while using React Context?
我的提供商有两个功能组件,
SubApp1
和 SubApp2
在这里,当我在 SubApp1
中增加 counter1 时,SubApp2
也在渲染,即使不需要重新渲染.
当我在 SubApp2
中增加 counter2 时,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>
);
}
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);
您应该将计数器作为道具传递给子应用程序。然后 memo 会注意只有更改了 props 的组件才会被重新渲染。
像这样:
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 link 不对...
我遵循 Peter Ambruzs 的提示,但如果我将 counter1 作为参数传递,我会遇到问题。组件不断重新渲染。
但是,如果我只传递 setCounter1 函数,它就可以正常工作。
下面是我使用打字稿的示例。
const Campaigns = (): JSX.Element => {
const { setAlert } = useContext(AlertContext);
return <InnerCampaign {...{ setAlert }} />;
};
const InnerCampaign = memo(
({ setAlert }: any): JSX.Element => {...},)
export default Campaigns;
我的提供商有两个功能组件,
SubApp1
和 SubApp2
在这里,当我在 SubApp1
中增加 counter1 时,SubApp2
也在渲染,即使不需要重新渲染.
当我在 SubApp2
中增加 counter2 时,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>
);
}
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);
您应该将计数器作为道具传递给子应用程序。然后 memo 会注意只有更改了 props 的组件才会被重新渲染。
像这样:
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 link 不对...
我遵循 Peter Ambruzs 的提示,但如果我将 counter1 作为参数传递,我会遇到问题。组件不断重新渲染。
但是,如果我只传递 setCounter1 函数,它就可以正常工作。
下面是我使用打字稿的示例。
const Campaigns = (): JSX.Element => {
const { setAlert } = useContext(AlertContext);
return <InnerCampaign {...{ setAlert }} />;
};
const InnerCampaign = memo(
({ setAlert }: any): JSX.Element => {...},)
export default Campaigns;