typescript React Router v6.10 -更改路由会丢失上一页的状态

omvjsjqw  于 2023-04-07  发布在  TypeScript
关注(0)|答案(1)|浏览(144)

所以我是React的新手,我现在正在学习路由。我创建了一个简单的应用程序,其中我有两个页面(Home和Todos),我通过标签栏在它们之间路由。在一个页面上,我有一个列表,我可以通过事件向其中添加数据。代码是:
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>
  )
}

现在的问题是,当我将数据添加到列表中时,转到主页,然后通过导航栏返回Todos页面,我之前添加的数据丢失了。为什么?我错过了什么?谢谢!(使用Ionic-React不会发生同样的事情,这就是为什么我认为我错过了什么)

zphenhs4

zphenhs41#

todos状态只是Todos组件中的本地状态,当你从"/todos"导航到"/home"时,todos路由不再匹配,因此Todos组件卸载。React状态不会持久化。
您可以将todos状态提升到一个公共祖先,无论匹配什么路由,该公共祖先都保持挂载状态,并将状态作为props向下传递。
示例:

const navigate = useNavigate();

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

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

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

    <nav className='tab-bar'>
      <div className='tab' onClick={() => router("/home")}>HOME</div>
      <div className='tab'  onClick={() => router("/todos")}>TODOS</div>
    </nav>
  </div>
);
interface TodosProps {
  todosList: TodoClass[];
  addTodo: TodoClass => void;
}

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

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

  const handleAddTaskButtonClick = (event: any) => {
    addTodo({ name: inputValue });
  }
    
  return (
    <div className='todos-cont'>
      <div className='list'>
        {todosList.map((item, index) => (
          <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>
  );
};

另一种方法是将本地todosList状态持久化到localStorage,并从localStorage初始化状态。当组件被挂载时,todosList状态被设置为持久化值或初始状态值[]。当更新时,使用useEffect钩子将状态持久化到localStorage。
示例:

function Todos() {
  const [todosList, addNewTodo] = useState<TodoClass[]>(() => {
    // Return persisted state value or default initial value
    return JSON.parse(localStorage.getItem("todosList")) ?? [];
  });

  useEffect(() => {
    if (todosList) {
      // Persist todosList state to localStorage
      localStorage.setItem("todosList", JSON.stringify(todosList));
    }
  }, [todosList]);

  ...
    
  return (
    ...
  );
}

相关问题