React Router v6.10 -改变路由失去前一页的状态



所以我对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>
)
}

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

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 (
...
);
}