你好,我有一个主题提供商,其中有两个主题与Emotion provider主题
,我有一个组件头,可以通过useTheme获得该主题:
const Header = () => {
const Theme = useTheme();
const [text, setText] = useState('');
console.log(Theme, 'this is header');
const handleClick = () => {
setText('');
};
return (
<Container theme={Theme}>
<Content theme={Theme} flexdirection={'column'}>
<textarea
onKeyPress={e => {
if (e.key === 'Enter') {
e.preventDefault();
}
if (e.key === 'Enter') {
handleClick();
}
}}
value={text}
onChange={e => setText(e.target.value)}
placeholder="Digite aqui sua mensagem"
/>
<Top theme={Theme} />
<NavBar theme={Theme} />
</Content>
</Container>
);
};
然后我将主题作为孩子的道具:
const NavBar = props => {
console.log(props.theme, 'this is nav bar');
return (
<Nav>
<ul>
<li>
<a href="#home">home</a>
</li>
<li>
<a href="#homex">test</a>
</li>
<li>
<a href="#homexv">test</a>
</li>
</ul>
</Nav>
);
};
但是在此组件中,我有一个文本字段,在键入时会在其中渲染,但是我的主题像gif一样一起渲染:
这是我控制主题的钩子:
export default function useAppTheme(defaultTheme = lightTheme) {
const [theme, _setTheme] = useState(getInitialTheme);
function getInitialTheme() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark' || savedTheme === 'light') {
return JSON.parse(savedTheme) === 'dark' ? darkTheme : defaultTheme;
} else {
return defaultTheme;
}
}
useEffect(() => {
localStorage.setItem('theme', JSON.stringify(theme.type));
}, [theme]);
return {
theme,
setTheme: ({ setTheme, ...theme }) => {
if (theme.type === 'dark') {
return _setTheme(darkTheme);
} else {
return _setTheme(lightTheme);
}
},
};
}
和我的主要组成部分:
export default function App() {
const { theme, setTheme } = useAppTheme();
useEffect(() => {
console.log('rendering app');
});
return (
<ThemeProvider theme={theme}>
<GlobalStyle />
<div className="App">
<Header />
<button
css={css`
background: red;
width: 100px;
height: 50px;
border-radius: 10px;
`}
onClick={() =>
setTheme(
theme.type === 'dark' ? { type: 'light' } : { type: 'dark' },
)
}
>
a
</button>
</div>
</ThemeProvider>
答案 0 :(得分:0)
据我了解,您的代码按预期运行。我想我可以解释如下。
由于状态更新(调用Header
onChange),重新呈现了 setText
。如果重新渲染了组件,则每个子组件都需要重新渲染(即使道具没有变化)。您可以使用shouldComponentUpdate
或成为PureComponent
或memoized function(al)
组件来退出此重新渲染。如我们所见,NavBar
在这里只是一个状态功能组件,它将在每次状态更新时重新呈现。有关详细信息,请参见here。
您可以使用React.memo
来解决此问题,如下所示:-
const NavBar = React.memo(props => {
console.log(props.theme, 'this is nav bar');
return (
<Nav>
<ul>
<li>
<a href="#home">home</a>
</li>
<li>
<a href="#homex">test</a>
</li>
<li>
<a href="#homexv">test</a>
</li>
</ul>
</Nav>
);
});
现在,除非实际更改道具,否则不会重新渲染组件。