React日期数组setState后不更新,返回表单无法增删日期
问题分析与解决方案
核心问题1:getDerivedStateFromProps 错误覆盖本地状态修改
你的getDerivedStateFromProps方法会在每次组件渲染前执行,当从其他步骤返回当前表单时,props.stepThree.dates已经有值(长度不为0),所以每次你尝试修改本地state.dates后,下一次渲染时这个方法会把state.dates重新设置为props中的值,直接覆盖了你刚刚做的修改,导致看起来状态完全没变化。
核心问题2:直接修改原数组,违反React状态不可变原则
在handleDayClick中,你直接对this.state.dates使用splice和push方法——这两个方法都是直接修改原数组,而React依赖状态的不可变更新来检测变化。当你调用setState({ dates })时,数组的引用没有改变,React可能会跳过重新渲染,或者无法正确识别状态变化。
具体修复步骤
1. 优化getDerivedStateFromProps逻辑
我们需要添加判断,只有当props中的dates和当前state中的dates真正不同时,才更新本地状态,避免不必要的覆盖:
static getDerivedStateFromProps = (nextProps, prevState) => { const { stepThree: { dates: propsDates } } = nextProps; // 仅当props有日期,且和当前state的日期内容不一致时才更新 if (propsDates.length > 0) { const convertedPropsDates = propsDates.map(date => new Date(date)); // 对比数组内容是否完全相同,避免无意义的重复更新 const isSame = convertedPropsDates.every((date, index) => DateUtils.isSameDay(date, prevState.dates[index]) ); if (!isSame) { return { dates: convertedPropsDates }; } } return null; };
2. 修复handleDayClick的状态更新方式
改用不可变的方式处理数组,创建新数组而非修改原数组,同时使用setState的函数式更新确保基于最新状态修改:
handleDayClick = (day, { selected }) => { this.setState(prevState => { const { dates } = prevState; if (selected) { // 过滤掉选中的日期,返回新数组 return { dates: dates.filter(selectedDay => !DateUtils.isSameDay(selectedDay, day)) }; } else { // 拼接新日期,返回新数组 return { dates: [...dates, day] }; } }); };
3. 确认reducer逻辑(可选)
你的reducer代码已经正确将日期转换为新的Date对象,这部分没有问题,只需确保ACTIONS.SET_STEP_THREE触发时传入的dates是正确的本地状态即可。
修复后的完整组件代码示例
class StepThree extends Component { static getDerivedStateFromProps = (nextProps, prevState) => { const { stepThree: { dates: propsDates } } = nextProps; if (propsDates.length > 0) { const convertedPropsDates = propsDates.map(date => new Date(date)); const isSame = convertedPropsDates.every((date, index) => DateUtils.isSameDay(date, prevState.dates[index]) ); if (!isSame) { return { dates: convertedPropsDates }; } } return null; }; state = { dates: [] }; handleDayClick = (day, { selected }) => { this.setState(prevState => { const { dates } = prevState; if (selected) { return { dates: dates.filter(selectedDay => !DateUtils.isSameDay(selectedDay, day)) }; } else { return { dates: [...dates, day] }; } }); }; handleNext = (e) => { e.preventDefault(); this.props.setStepThree(this.state.dates); }; render() { return ( <Col> <Col style={{ textAlign: 'center' }}> <DayPicker selectedDays={this.state.dates} onDayClick={this.handleDayClick} /> </Col> <div style={{ width: '100%', position: 'fixed', bottom: '0px', zIndex: '100', textAlign: 'center', padding: '10px', left: '0px' }} > <PreviousButton handleClick={this.props.handlePrevious} /> <NextButton handleClick={this.handleNext} /> </div> </Col> ); } }
这样修改后,当你返回表单时,getDerivedStateFromProps只会在props日期真正变化时更新本地状态,而你的日期修改操作也会正确触发状态更新,不会被覆盖。
内容的提问来源于stack exchange,提问作者Tarang Hirani
相关产品推荐
相关产品推荐

