useState
возвращает новый массив при каждом вызове.Таким образом, вы передаете новый массив в контекст каждого рендера. используйтеMemo для решения проблемы.
var themes = {
light: {
name: "Light",
foreground: "#000000",
background: "#eeeeee"
},
dark: {
name: "Dark",
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext({
theme: themes.light,
updateTheme: () => {}
});
let prevTheme = undefined;
let prevStateArray = undefined;
function App() {
console.log("RE-RENDERING App...");
const stateArray = React.useState(themes.light);
console.log('stateArray', prevStateArray, stateArray, Object.is(prevStateArray, stateArray));
prevStateArray = stateArray;
const [theme, setTheme] = stateArray;
const memoState = React.useMemo(() => [theme, setTheme], [theme, setTheme]);
const [otherState, setOtherState] = React.useState(true);
function handleSetOtherState() {
console.log("SETTING OTHER STATE.....");
setOtherState(prevState => !prevState);
}
console.log("theme:", theme);
console.log("prevTheme:", prevTheme);
console.log(`Object.is(prevTheme, theme): ${Object.is(prevTheme, theme)}`);
prevTheme = theme;
return (
<ThemeContext.Provider value={memoState}>
<Toolbar />
<button onClick={handleSetOtherState}>Change OtherState</button>
</ThemeContext.Provider>
);
}
class Toolbar extends React.PureComponent {
render() {
console.log("RE-RENDERING Toolbar (DOES NOT HAPPEN WHEN CHANGING OTHERSTATE)...");
return (
<div>
<ThemedButton />
</div>
);
}
}
function ThemedButton() {
console.log("RE-RENDERING ThemedButton (SHOULD NOT HAPPEN WHEN CHANGING OTHERSTATE)...");
const themeContext = React.useContext(ThemeContext);
const [theme, setTheme] = themeContext;
console.log("themeContext:", themeContext);
console.log("theme.name:", theme.name);
console.log("setTheme:", setTheme);
function handleToggleTheme() {
console.log("SETTING THEME STATE.....");
setTheme(
prevState =>
themes.dark
);
}
return <button onClick={handleToggleTheme}>Click me: {theme.name}</button>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"/>