React Router Dom V6同组件路由导航时useState状态未重置问题
React Router Dom V6同组件路由切换状态未重置的解决方案
问题场景
创建和编辑用户共用UserForm组件,对应路由为/user(创建)和/user/:id(编辑)。从编辑路由导航到创建路由时,组件内useState状态未重置,仍保留编辑页面的值;仅刷新页面时状态才会正常初始化。
路由配置:
<Route path='user/:id' element={<UserForm />} /> <Route path='user' element={<UserForm />} />
组件核心代码:
const UserForm = () => { const navigate = useNavigate(); const params = useParams<FormParams>(); const [loading, setLoading] = useState<boolean>(true); const [message, setMessage] = useState<MessageProps>(); const [data, setData] = useState<UserModel>(newData); // ...其他逻辑 }
导航函数:
const newForm = () => { try { navigate('/user'); } catch (error) { console.log("ERROR"); } }
问题原因
React Router切换同组件实例的路由时,不会执行卸载-重新挂载流程,而是复用已有组件实例,因此useState初始值仅在第一次挂载时生效,后续路由切换不会重新初始化状态。
解决方案
1. 给组件添加key属性强制重新挂载
通过给路由中的UserForm设置唯一key(基于路由路径或参数),让React识别为不同组件实例,触发卸载-重新挂载以重置状态:
<Route path='user/:id' element={<UserForm key={window.location.pathname} />} /> <Route path='user' element={<UserForm key={window.location.pathname} />} />
或精准根据参数设置key:
const UserFormRoute = () => { const params = useParams<FormParams>(); return <UserForm key={params.id ?? 'create'} />; }; <Route path='user/:id' element={<UserFormRoute />} /> <Route path='user' element={<UserForm key='create' />} />
2. 监听路由变化手动重置状态
在UserForm组件中用useEffect监听路由参数或路径变化,手动重置状态:
const UserForm = () => { const navigate = useNavigate(); const params = useParams<FormParams>(); const [loading, setLoading] = useState<boolean>(true); const [message, setMessage] = useState<MessageProps>(); const [data, setData] = useState<UserModel>(newData); // 监听路由id参数变化,重置创建页面状态 useEffect(() => { if (!params.id) { setData(newData); setMessage(undefined); setLoading(true); } // 编辑页面可在此添加加载用户数据逻辑 }, [params.id]); // ...其他逻辑 }
若需每次路由切换都重置状态,可加入location.pathname作为依赖:
import { useLocation } from 'react-router-dom'; const UserForm = () => { const location = useLocation(); // ... useEffect(() => { setData(newData); setMessage(undefined); setLoading(true); }, [location.pathname]); }
3. 拆分组件复用逻辑(可选)
将创建、编辑拆为独立组件,通过自定义Hook复用核心逻辑,路由切换时组件重新挂载自然初始化状态:
// 抽离表单逻辑的自定义Hook const useUserFormLogic = (userId?: string) => { const [loading, setLoading] = useState<boolean>(true); const [message, setMessage] = useState<MessageProps>(); const [data, setData] = useState<UserModel>(newData); useEffect(() => { if (userId) { // 加载编辑用户数据 fetchUserById(userId).then(res => { setData(res); setLoading(false); }); } else { // 创建页面重置数据 setData(newData); setLoading(false); } }, [userId]); // 提交表单等逻辑 const handleSubmit = () => { /* ... */ }; return { loading, message, data, setData, handleSubmit }; }; // 创建用户组件 const CreateUserForm = () => { const formLogic = useUserFormLogic(); return <UserFormUI {...formLogic} />; }; // 编辑用户组件 const EditUserForm = () => { const params = useParams<FormParams>(); const formLogic = useUserFormLogic(params.id); return <UserFormUI {...formLogic} />; }; // 路由配置 <Route path='user/:id' element={<EditUserForm />} /> <Route path='user' element={<CreateUserForm />} />
内容的提问来源于stack exchange,提问作者Lucas K C
相关产品推荐
相关产品推荐

