React项目中同步Redux数据与useState显隐状态的实现问题
问题根源
- 你定义的
education_vis是组件渲染过程中生成的临时局部变量,每次组件重渲染都会被重新初始化,修改它不会触发组件更新,自然界面不会响应切换操作。 - 你之前设置的useEffect依赖
education_vis无效,因为普通JS变量不是React的响应式状态,它的变更不会触发effect执行。 - 首次组件渲染时Redux中的
education_data还未加载完成,是空数组,所以初始化的可见性状态长度和后续加载完成的真实数据长度不一致,导致不同步。
解决方案
你只需要按如下逻辑修改代码即可:
import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from "react-redux"; import * as educationActions from "../../actions/educationActions"; import DeleteButton from "./deleteButton"; import UpdateButton from "./updateButton"; import VisibilityOffIcon from '@material-ui/icons/VisibilityOff'; import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom"; import EducationForm from "../forms/updateForms/educationForm"; const Education = () => { const dispatch = useDispatch(); const [educationVisibility, setEducationVisibility] = useState([]); useEffect(() => { const userEducation = async () => { await dispatch(educationActions.getEducation('60fcc884bbed863d20b02573')); }; userEducation(); }, [dispatch]); const education_data = useSelector((state) => state.education.education); // 监听Redux返回的education_data变化,同步更新可见性数组 useEffect(() => { setEducationVisibility(prevVis => { // 保留原有条目的显隐状态,新增的条目默认设为可见 const newVis = [...prevVis]; for(let i = prevVis.length; i < education_data.length; i++){ newVis.push(true); } // 如果数据长度变短,截断可见性数组 return newVis.slice(0, education_data.length); }) }, [education_data]) const handleChange = (index) => { setEducationVisibility(prevVis => { const newVis = [...prevVis]; newVis[index] = !newVis[index]; return newVis; }) } return ( <Router> <div> <p> Education </p> <hr /> {education_data.map((value, index) => { return ( <div key={value._id}> <VisibilityOffIcon onClick = {()=>handleChange(index)} /> {educationVisibility[index] ? <div> <p>{ value.university_name }, { value.university_city }, { value.university_state } { value.month_begin } { value.year_begin } - { value.month_end } { value.year_end }</p> <p>{ value.degree_name } in { value.domain_name } { value.GPA }</p> <DeleteButton elementId = { value._id } page = { "Education" }/> <Link to={ `/education/${value._id}/update` } ><UpdateButton /></Link> </div> : null} </div> ) })} </div> <Switch> <Route path="/education/:elementId/update"> <EducationForm /> </Route> </Switch> </Router> ) } export default Education
核心修改说明
- 把
educationVisibility作为唯一的显隐控制状态,移除原来的临时变量education_vis。 - useEffect依赖改为
education_data,只有Redux中的教育数据发生变更时,才更新可见性数组,并且保留用户之前设置过的显隐状态,不会因为数据更新就重置所有条目为可见。 handleChange中通过setEducationVisibility返回新数组的方式修改状态,触发组件重渲染更新界面。- 把
key属性移到map返回的最外层DOM节点上,避免React警告,优先使用数据唯一标识_id作为key,不要用索引。
内容的提问来源于stack exchange,提问作者Ayush Arora
相关产品推荐
相关产品推荐

