React中useLocation传数据到useState引发无限循环的解决方案
解决React Router通过
location.state传参后追加数据导致的无限循环问题 我明白你遇到的问题了——直接在组件渲染流程里调用setUsers处理路由传来的location.state,会触发组件重渲染,而重渲染又会再次执行这段逻辑,最终陷入无限循环。咱们用useEffect就能完美解决这个问题,下面一步步来:
问题根源
你现在的代码里,这段逻辑是在组件每次渲染时都会执行的:
if (location.state !== null) { setUsers([...users, location.state]); location.state = null; }
每次调用setUsers都会更新组件状态、触发重新渲染,而重渲染后又会重新检查location.state(另外直接修改location.state是无效的,因为useLocation返回的是路由维护的不可变对象),所以就陷入了无限循环。
解决方案:用useEffect监听location.state
把处理路由传参的逻辑放到useEffect中,只在location.state有值的时候执行一次,并且用navigate.replace清除路由状态,避免用户刷新页面后重复添加数据。
修改后的List组件代码:
import React, { useEffect, useState } from "react"; import "../style.css"; import { useNavigate, useLocation } from "react-router-dom"; export default function List() { const [users, setUsers] = useState([]); const navigate = useNavigate(); const location = useLocation(); // 从API获取初始用户数据 useEffect(() => { async function fetchData() { const response = await fetch( "https://jsonplaceholder.typicode.com/users" ); const data = await response.json(); setUsers(data); } fetchData(); }, []); // 处理路由传来的新用户数据 useEffect(() => { // 校验state是否为有效用户对象,避免空值或错误数据 if (location.state?.name && location.state?.email && location.state?.website) { // 使用函数式更新,确保拿到最新的users状态 setUsers(prevUsers => [...prevUsers, location.state]); // 用replace清除路由state,避免刷新/后退时重复处理 navigate(0, { replace: true, state: null }); } }, [location.state, navigate]); function onClickHandler(e) { navigate("/Form"); } return ( <> <div className="container"> <h1>Contacts</h1> <table> <thead> <tr> <th>Name</th> <th>Email</th> <th>Website</th> </tr> </thead> <tbody> {users.map((user, index) => { return ( <tr key={index}> <td>{user.name}</td> <td>{user.email}</td> <td>{user.website}</td> </tr> ); })} </tbody> </table> </div> <button onClick={onClickHandler}>Add Contact</button> </> ); }
关键说明:
- 函数式更新state:用
setUsers(prevUsers => [...prevUsers, location.state])而非直接使用users数组,这样能确保我们总是基于最新的状态进行更新,避免闭包导致的旧状态问题。 - useEffect依赖控制:把
location.state和navigate加入依赖数组,这样只有当location.state变化时,这个effect才会执行,避免不必要的重复触发。 - 清除路由state:用
navigate(0, { replace: true, state: null })替换当前路由的状态,这样用户刷新页面或后退再前进时,不会再次触发添加逻辑,因为state已经被清空了。
这样修改后,就能安全地把Form组件传来的用户数据追加到列表里,而且不会出现无限循环的问题啦!
内容的提问来源于stack exchange,提问作者user17958456
相关产品推荐
相关产品推荐

