我正在创建一个待办事项列表应用程序,将数据保存在本地存储中,但当我重新加载页面时,我的组件呈现两次,创建空数据并替换为保存在本地存储中的先前任务。
这是我的主文件:main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import './scss/styles.scss';
import * as bootstrap from 'bootstrap';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
也是main.jsx的子级:App.jsx
import React from 'react';
import ToDo from './Components/ToDo';
const App = () => (
<div className="container-fluid col-md-5 mx-auto" data-bs-theme="dark">
<h1 className="text-center fw-bold">
To do app
</h1>
<ToDo />
</div>
);
export default App;
这是App.jsx的子级:ToDo.jsx
import React, { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faListCheck, faCirclePlus } from '@fortawesome/free-solid-svg-icons';
import SimpleToast from './Alerts/SimpleToast';
import Items from './Items';
const ToDo = () => {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');
useEffect(() => {
const storedTasks = localStorage.getItem('tasks');
if (storedTasks) {
setTasks(JSON.parse(storedTasks));
}
}, []);
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks));
}, [tasks]);
const handleAddTask = (event) => {
event.preventDefault();
if (newTask.trim() === '') {
SimpleToast.fire({
icon: 'error',
title: 'Enter a task first',
});
return;
}
setTasks([...tasks, { id: Date.now(), text: newTask, completed: false }]);
setNewTask('');
};
const handleDeleteTask = (taskId) => {
const updatedTasks = tasks.filter((task) => task.id !== taskId);
setTasks(updatedTasks);
};
return (
<>
<form onSubmit={handleAddTask}>
<div className="form-floating position-relative">
<input
id="new-task"
type="text"
className="form-control shadow-lg"
placeholder="Enter a new task"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
/>
<label htmlFor="new-task">
Enter a new task
{' '}
<FontAwesomeIcon icon={faListCheck} />
</label>
<button
type="submit"
className="btn position-absolute top-50 end-0 translate-middle"
>
<FontAwesomeIcon
type="submit"
className="position-absolute translate-middle fs-3"
icon={faCirclePlus}
/>
</button>
</div>
</form>
<Items tasks={tasks} handleDeleteTask={handleDeleteTask} />
</>
);
};
export default ToDo;
还有项目组成部分:
import React from 'react';
import Item from './Item';
const Items = ({ tasks, handleDeleteTask }) => (
<ul className="list-group-flush bg-white rounded shadow-lg my-3 p-3">
{tasks.length === 0 ? <li className="text-center list-group-item"> No tasks</li> : tasks.map((task) => (
<Item key={task.id} task={task.text} handleDeleteTask={handleDeleteTask} idTask={task.id} />
))}
</ul>
);
export default Items;
和项目组件:
import React, { useState, useEffect } from 'react';
import { faPen, faTrash, faFloppyDisk } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const Item = ({ task, handleDeleteTask, idTask }) => {
const [text, setText] = useState('');
const [isEdit, setIsEdit] = useState(false);
const [isSelected, setIsSelected] = useState(false);
useEffect(() => {
setText(task);
}, [task]);
const handleEdit = () => {
if (!isEdit) {
setIsEdit(true);
return;
}
setIsEdit(false);
};
const handleCheckTask = () => {
if (!isSelected) {
setIsSelected(true);
return;
}
setIsSelected(false);
};
return (
<li className="row border rounded shadow-md p-1 my-2">
<div className="col-1 p-0 text-center align-middle">
<input className="form-check-input align-middle" type="checkbox" onChange={() => handleCheckTask()} />
</div>
<div className="col-9 p-0">
<input className={`form-control border-0 text-dark ${isSelected ? 'text-decoration-line-through' : 'text-decoration-none'}`} value={text} type="text" onChange={(e) => setText(e.target.value)} disabled={!isEdit} />
</div>
<div className="col-1 p-0">
<button type="button" className="btn" onClick={() => handleEdit()}>
<FontAwesomeIcon className="text-danger" icon={!isEdit ? faPen : faFloppyDisk} />
</button>
</div>
<div className="col-1 p-0">
<button type="button" className="btn">
<FontAwesomeIcon className="text-danger" icon={faTrash} onClick={() => handleDeleteTask(idTask)} />
</button>
</div>
</li>
);
};
export default Item;
我已经尝试在Todo.jsx
中记录第一个useEffect console.log(storedTasks)
,当我重新加载时,我可以在控制台中看到以前的任务,但在那之后,我认为一个新的空数组正在替换第一个数组。
3条答案
按热度按时间yftpprvb1#
看起来你每次加载的时候都用默认值覆盖了任务。一个快速简单的解决方案是,如果你改变你的第二个useEffect只在一个有效的任务上运行,比如,如果任务中有一个值,或者如果任务被定义了。
您需要将任务定义为未定义
渲染
在渲染时,当任务未定义时,我们使用逻辑或
||
来渲染0任务汇总代码
8yparm6h2#
尝试使用
storedTasks.length
代替storedTask
,因为空数组的Boolean
是true
。gv8xihay3#
我认为以下几点
可能会在第一次触发,以及它上面的useEffect,并且由于setTasks在执行此代码时可能尚未生效,因此tasks将为
[]
。我建议直接执行
localStorage.setItem
,在handleAddTask
中更改状态。注意,我没有使用
tasks
,因为setTasks可能在执行该行时还没有生效。