useEffect不执行求助:传递ThemeChange对象后未触发回调
解决useEffect依赖对象不触发的问题
你的代码核心问题是React对useEffect依赖数组采用浅引用比较:
- 每次组件重渲染时,你都会创建新的
ThemeChange对象(哪怕属性值和上一次完全一致) - 你遇到的useEffect不触发情况,大概率是对依赖比较逻辑的误解——理论上每次重渲染这个新对象都会触发useEffect,但如果你的需求是仅当主题实际样式变化时触发,当前写法就不符合预期。
方案1:直接依赖状态值(推荐)
既然ThemeChange的所有属性都由dark状态决定,直接把dark作为useEffect的依赖项,这样只有当主题状态真正变化时,useEffect才会执行:
import React,{useState, useMemo, useEffect} from 'react' import './App.css'; function App() { const [dark, setDark] = useState(false), [number, setNumber] = useState(0) const SlowFunction = num => { for(let i=1; i<=10000; ++i) {} return num*2 } const TwiceNo = useMemo(() => { return SlowFunction(number) }, [number]) const ThemeChange = { backgroundColor : dark ? 'black' : 'white', color : dark ? 'white' : 'black' } useEffect(() => { console.log('theme was changed!') }, [dark]) // 改为依赖dark状态 return ( <div className="App"> <input type="number" onChange = {e => {setNumber(parseInt(e.target.value), console.log(e))}} /> <button onClick={() => setDark(e => !e)}>toggle theme</button> <div style={ThemeChange}>{TwiceNo}</div> </div> ); } export default App;
方案2:用useMemo缓存ThemeChange对象
如果你必须依赖ThemeChange对象本身,可以用useMemo缓存这个对象,确保只有当dark变化时,对象的引用才会更新,避免不必要的useEffect触发:
import React,{useState, useMemo, useEffect} from 'react' import './App.css'; function App() { const [dark, setDark] = useState(false), [number, setNumber] = useState(0) const SlowFunction = num => { for(let i=1; i<=10000; ++i) {} return num*2 } const TwiceNo = useMemo(() => { return SlowFunction(number) }, [number]) // 用useMemo缓存对象,仅当dark变化时重新创建 const ThemeChange = useMemo(() => ({ backgroundColor : dark ? 'black' : 'white', color : dark ? 'white' : 'black' }), [dark]) useEffect(() => { console.log('theme was changed!') }, [ThemeChange]) return ( <div className="App"> <input type="number" onChange = {e => {setNumber(parseInt(e.target.value), console.log(e))}} /> <button onClick={() => setDark(e => !e)}>toggle theme</button> <div style={ThemeChange}>{TwiceNo}</div> </div> ); } export default App;
补充说明
原来的写法中,每次组件重渲染(比如修改number)都会生成新的ThemeChange对象,即使属性值没变化,React也会认为依赖项发生了改变,理论上会触发useEffect。如果你发现useEffect完全没执行,建议检查控制台是否有其他输出干扰,或者确认组件是否真的发生了重渲染。
内容的提问来源于stack exchange,提问作者Prabhdeep Singh
相关产品推荐
相关产品推荐

