React Redux的uireducer状态变更后未触发组件重新渲染问题
问题原因及解决方法
1. 组件副作用依赖项遗漏
你当前组件里的useEffect依赖数组是空数组[],这代表该副作用仅会在组件首次挂载时执行一次。后续即便activeSubject或data props发生变化,useEffect也不会重新执行,本地的topics状态永远不会更新,因此界面不会触发预期的变化。
解决方法:将activeSubject和data加入useEffect的依赖数组,同时可以加边界判断避免报错:
useEffect(() => { console.log('Active Subject : ', activeSubject); if(activeSubject && data.length){ const matchSubject = data.find(subject => subject.id === activeSubject) if(matchSubject) { console.log('Data : ', matchSubject.topics); setTopics(matchSubject.topics) } } }, [activeSubject, data])
2. uireducer 状态读取错误
你使用combineReducers拆分状态后,每个reducer仅能拿到自己负责的那部分状态:uireducer接收的state参数本身就是{activeSubject, activeTopic}结构,不存在额外的uireducer属性,因此SET_ACTIVE_TOPIC分支里的state.uireducer.activeSubject写法错误,会读取到undefined。
解决方法:修改uireducer的对应分支:
case SET_ACTIVE_TOPIC: return makeState(state.activeSubject, action.payload)
优化建议
你完全可以直接在渲染时通过props计算得到需要展示的topics,不需要额外用本地state存储,既减少冗余代码,也避免依赖遗漏的问题,简化后的组件代码如下:
const Topics = ({activeSubject, data}) => { const classes = useStyles() // 直接计算topics,无需本地state和useEffect const topics = activeSubject ? (data.find(subject => subject.id === activeSubject)?.topics || []) : [] return ( <List> { topics.length > 0 ? topics.map(topic => { return ( <ListItem button className={classes.listItem} id={topic.id} key={topic.id}> {topic.name} <ButtonGroup className={classes.editDelete}> <IconButton className={classes.icon}> <Edit /> </IconButton> <IconButton className={classes.icon}> <Delete /> </IconButton> </ButtonGroup> </ListItem> ) }) : <div className={classes.waitMessage}><p>Select Subject To Display Topics</p></div> } </List> ) } const mapStateToProps = state => ({ activeSubject: state.uireducer.activeSubject, data: state.subjects.data }) export default connect(mapStateToProps)(Topics);
内容的提问来源于stack exchange,提问作者Sushil Shinde
相关产品推荐
相关产品推荐

