修改state后useEffect Hook未触发,如何让其每次变更都触发?
解决useEffect未触发的问题
问题根源
你的代码存在两个关键问题:
- Hook调用顺序违反规则:React要求所有Hook(
useState、useEffect等)必须在组件的顶层作用域调用,不能在普通函数、条件判断或其他Hook之后。你把useState声明放在了useEffect和decrease_day函数之后,这会导致React无法正确追踪state的变更,进而影响useEffect的触发逻辑。 - 闭包可能导致的state更新问题:如果
diminution_day_1_pour_calculs是基于当前day_1计算的,直接使用可能会捕获旧的state值,导致更新后的值和之前一致(这种情况下useEffect也不会触发)。
修复步骤
- 调整Hook顺序:把所有
useState声明移到组件最顶部,确保在任何其他逻辑(useEffect、自定义函数)之前调用。 - 使用函数式更新获取最新state:如果新state依赖当前state,用
setday_1(prev => ...)的形式,避免闭包捕获旧值。 - 确认日期计算逻辑正确:确保每次调用
decrease_day时,生成的日期字符串确实和当前day_1/day_2不同(如果值完全相同,useEffect不会触发)。
修改后的完整代码
import { useState, useEffect } from 'react'; import moment from 'moment'; import { View, TouchableOpacity, Text } from 'react-native'; export default function Calendrier() { // 把useState移到组件最顶层 const [day_1, setday_1] = useState(''); const [day_2, setday_2] = useState(''); useEffect(() => { setday_1(moment(new Date()).format("DD/MM/YYYY")); setday_2(moment(new Date()).add(1, 'days').format("DD/MM/YYYY")); }, []); useEffect(() => { console.log('is called ?', day_1, day_2); }, [day_1, day_2]); function decrease_day () { // 用函数式更新确保拿到最新的state值,基于当前日期减一天 setday_1(prevDay => moment(prevDay, "DD/MM/YYYY").subtract(1, 'days').format("DD/MM/YYYY")); setday_2(prevDay => moment(prevDay, "DD/MM/YYYY").subtract(1, 'days').format("DD/MM/YYYY")); } return ( <View style={styles.principal}> <TouchableOpacity style={styles.icon_day_1} onPress={decrease_day}> <Text>减一天</Text> </TouchableOpacity> <View style={styles.text_day_1}> <Text>{day_1}</Text> </View> <View style={styles.day_2}> <View style={styles.text_day_2}> <Text>{day_2}</Text> </View> </View> </View> ); } // 示例样式定义 const styles = { principal: { flex: 1, justifyContent: 'center', alignItems: 'center', gap: 16 }, icon_day_1: { padding: 12, backgroundColor: '#eee', borderRadius: 8 }, text_day_1: { padding: 8 }, day_2: { padding: 8 } };
关键说明
- Hook顺序的重要性:React通过Hook的调用顺序来关联组件的状态和副作用,一旦顺序混乱,React的Hook机制就会失效,导致state变更无法被正确监听。
- 函数式更新的作用:当新的state值依赖于当前state时,必须使用函数式更新,确保拿到最新的state值,避免闭包导致的旧值问题,同时保证每次更新后的值唯一,触发useEffect执行。
内容的提问来源于stack exchange,提问作者Eragon
相关产品推荐
相关产品推荐

