You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router v6.10切换路由丢失页面状态问题求助

React路由切换后Todos数据丢失的原因及解决办法

我是React新手,正在学习路由相关知识。我做了一个简单应用,包含Home和Todos两个页面,通过Tab Bar切换路由。在Todos页面可以添加数据到列表,但切换到Home再切回Todos时,之前添加的数据就没了。用Ionic-React时不会出现这个问题,想知道原因和解决办法。

相关代码

App.tsx

const router = useNavigate();
return (
    <div className='app-main-cont'>
      <div className='app-main-content'>
        <Routes>
          <Route path='/' element={<Navigate replace to='/home'/>}></Route>
          <Route path='/home' element={<Home/>}></Route>
          <Route path='/todos' element={<Todos/>}></Route>
        </Routes>
      </div>

      <nav className='tab-bar'>
        <div className='tab' onClick={()=>{router('/home')}}>HOME</div>
        <div className='tab'  onClick={()=>{router('/todos')}}>TODOS</div>
      </nav>
    </div>
  )

Todos.tsx

function Todos() {

  const [todosList, addNewTodo] = useState<TodoClass[]>([]);
  const [inputValue, changeInputValue] = useState('');

  const handleChangeEvent = (event: ChangeEvent) => {
    const val = (event.target) as HTMLInputElement;
    changeInputValue(val.value);
  }

  const handleAddTaskButtonClick = (event: any) => {
    let obj: TodoClass = {name: inputValue};
    addNewTodo([...todosList, obj]);
  }
    
  return (
    <div className='todos-cont'>
      <div className='list'>
        {todosList.map((item, index) => {
            return (
              <div className='list-item' key={index}>
                {item.name}
              </div>
            )
          })}
      </div>

      <div className='add-todo'>
          <div className='input-todo'>
            <input type="text" placeholder='Input a todo task' onChange={handleChangeEvent} />
          </div>
          <div className='add-btn' onClick={handleAddTaskButtonClick}>
            ADD
          </div>
        </div>
    </div>
  )
}

问题原因

这是因为React Router切换路由时,未匹配的路由组件会被卸载。你的todosList状态存在Todos组件内部的useState里,当切换到Home页面,Todos组件被卸载,状态就会被销毁;切回Todos时,组件重新挂载,useState会重新初始化,所以数据就丢了。

而Ionic-React的路由默认带有组件缓存机制(类似Vue的keep-alive),切换路由时组件不会被卸载,状态自然保留。

解决办法

有几种常见方案:

1. 状态提升到父组件

把todosList的状态移到App.tsx中,通过props传递给Todos组件,这样组件卸载时状态存在父组件里,不会丢失:

修改App.tsx:

function App() {
  const router = useNavigate();
  const [todosList, setTodosList] = useState<TodoClass[]>([]);

  const addNewTodo = (todo: TodoClass) => {
    setTodosList([...todosList, todo]);
  }

  return (
    <div className='app-main-cont'>
      <div className='app-main-content'>
        <Routes>
          <Route path='/' element={<Navigate replace to='/home'/>}></Route>
          <Route path='/home' element={<Home/>}></Route>
          <Route path='/todos' element={<Todos todosList={todosList} addNewTodo={addNewTodo}/>}></Route>
        </Routes>
      </div>

      <nav className='tab-bar'>
        <div className='tab' onClick={()=>{router('/home')}}>HOME</div>
        <div className='tab'  onClick={()=>{router('/todos')}}>TODOS</div>
      </nav>
    </div>
  )
}

修改Todos.tsx:

interface TodosProps {
  todosList: TodoClass[];
  addNewTodo: (todo: TodoClass) => void;
}

function Todos({ todosList, addNewTodo }: TodosProps) {
  const [inputValue, changeInputValue] = useState('');

  const handleChangeEvent = (event: ChangeEvent) => {
    const val = (event.target) as HTMLInputElement;
    changeInputValue(val.value);
  }

  const handleAddTaskButtonClick = (event: any) => {
    let obj: TodoClass = {name: inputValue};
    addNewTodo(obj);
    changeInputValue(''); // 清空输入框
  }
    
  return (
    <div className='todos-cont'>
      <div className='list'>
        {todosList.map((item, index) => {
            return (
              <div className='list-item' key={index}>
                {item.name}
              </div>
            )
          })}
      </div>

      <div className='add-todo'>
          <div className='input-todo'>
            <input type="text" placeholder='Input a todo task' onChange={handleChangeEvent} value={inputValue}/>
          </div>
          <div className='add-btn' onClick={handleAddTaskButtonClick}>
            ADD
          </div>
        </div>
    </div>
  )
}

2. 使用本地存储持久化数据

如果希望页面刷新后数据也不丢失,可以用localStorage或sessionStorage保存数据,组件挂载时读取,更新时同步存储:

修改Todos.tsx:

function Todos() {
  // 挂载时从localStorage读取数据
  const [todosList, addNewTodo] = useState<TodoClass[]>(() => {
    const saved = localStorage.getItem('todosList');
    return saved ? JSON.parse(saved) : [];
  });
  const [inputValue, changeInputValue] = useState('');

  const handleChangeEvent = (event: ChangeEvent) => {
    const val = (event.target) as HTMLInputElement;
    changeInputValue(val.value);
  }

  const handleAddTaskButtonClick = (event: any) => {
    let obj: TodoClass = {name: inputValue};
    const newList = [...todosList, obj];
    addNewTodo(newList);
    // 同步到localStorage
    localStorage.setItem('todosList', JSON.stringify(newList));
    changeInputValue('');
  }
    
  return (
    <div className='todos-cont'>
      <div className='list'>
        {todosList.map((item, index) => {
            return (
              <div className='list-item' key={index}>
                {item.name}
              </div>
            )
          })}
      </div>

      <div className='add-todo'>
          <div className='input-todo'>
            <input type="text" placeholder='Input a todo task' onChange={handleChangeEvent} value={inputValue}/>
          </div>
          <div className='add-btn' onClick={handleAddTaskButtonClick}>
            ADD
          </div>
        </div>
    </div>
  )
}

3. 使用全局状态管理

如果应用规模较大,可以用React Context、Redux、Zustand等全局状态管理工具,把todos数据放到全局状态中,任何组件都可以访问和修改。

内容的提问来源于stack exchange,提问作者akamzel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:24:54