React todo存localStorage后刷新前端无法正常渲染问题求助
React待办应用问题修复方案
核心问题原因
- useState初始化错误:从localStorage读取的
inittodos本身就是数组类型,初始化useState时额外多套了一层数组,导致todoslist始终是二维数组结构[[todo项1, todo项2...]],遍历渲染时只能拿到外层的第一个数组元素,自然只会显示单个todo,也无法正确读取todo的属性值。 - 组件命名不匹配:App组件中导入的组件名为
Addtodo,但实际组件导出的名称是Add_todo,命名不一致会导致组件加载异常。 - 缺失ondelete函数定义:App组件中传给Todos组件的
ondelete方法没有声明,运行时会直接报错。
修复步骤
- 修正useState初始化逻辑,将App组件中:
const [todoslist, settodos] = useState([inittodos]);
修改为
const [todoslist, settodos] = useState(inittodos);
- 统一组件命名,要么将App组件的导入语句改为
import { Add_todo as Addtodo } from "./my-components/addtodo";,要么直接修改Add_todo组件的导出名称为Addtodo。 - 在App组件中补全ondelete函数逻辑,示例如下:
const ondelete = (targetTodo) => { settodos(todoslist.filter(item => item.task !== targetTodo.task)) }
- (可选优化)修正Add_todo组件中task_name输入框的类型错误,将
type="textl"改为type="text"。
修复后完整代码
App.js
import './App.css'; import Header from "./my-components/header.js"; import Todos from "./my-components/todos"; import Footer from "./my-components/footer"; import { Add_todo as Addtodo } from "./my-components/addtodo"; import React, { useState, useEffect } from 'react'; function App() { let inittodos; if (localStorage.getItem("todoslist") === null) { inittodos = []; } else { inittodos = JSON.parse(localStorage.getItem("todoslist")); } const addtodo = (task, task_name, members) => { let newtodo = { task: task, task_name: task_name, members: members }; settodos([...todoslist, newtodo]); } const ondelete = (targetTodo) => { settodos(todoslist.filter(item => item.task !== targetTodo.task)) } const [todoslist, settodos] = useState(inittodos); useEffect(() => { localStorage.setItem("todoslist", JSON.stringify(todoslist)); }, [todoslist]); return ( <> <Header title="Learnig-React" search_bar={true} /> <Addtodo addtodo={addtodo} /> <Todos todos={todoslist} ondelete={ondelete} /> <Footer /> </> ); } export default App;
addtodo.js
import React, { useState } from 'react' export const Add_todo = ({ addtodo }) => { const [task, settask] = useState(""); const [task_name, settask_name] = useState(""); const [members, setmembers] = useState(""); //submit function for storing contents onclick on submit button const submit = (e) => { e.preventDefault(); if (!task || !task_name || !members) { alert("Plese fill all details"); } else { addtodo(task, task_name, members); settask(""); settask_name(""); setmembers("") } } return ( <div className="container"> <form onSubmit={submit}> <div className="form-group"> <label htmlFor="task">Task</label> <input type="text" id="task" className="form-control" aria-describedby="emailHelp" value={task} onChange={(e) => { settask(e.target.value) }} placeholder="Enter Task" /> <small id="" className="form-text text-muted">We'll never share your email with anyone else.</small> </div> <div className="form-group"> <label htmlFor="task_name">Task-Name</label> <input type="text" id="task_name" className="form-control" aria-describedby="emailHelp" value={task_name} onChange={(e) => { settask_name(e.target.value) }} placeholder="Enter Task Name" /> <small id="" className="form-text text-muted">We'll never share your email with anyone else.</small> </div> <div className="form-group"> <label htmlFor="members">Members</label> <input type="number" id="members" className="form-control" aria-describedby="emailHelp" value={members} onChange={(e) => { setmembers(e.target.value) }} placeholder="Enter No. Members" /> <small id="" className="form-text text-muted">We'll never share your email with anyone else.</small> </div> <button type="submit" className="btn-sm btn-success my-3">Submit</button> </form> </div> ) }
内容的提问来源于stack exchange,提问作者Akram
相关产品推荐
相关产品推荐

