I have a todo list app and am trying to fetch the tasks from the backend when the component renders. However, the data is duplicated and I can't understand why. Could it be because the useEffect hook is being called twice? I suspect because when the observable changes, the observer rerenders so it might be being called a second time, but then wouldn't it become an infinite loop? So I don't quite understand.
TaskList.tsx:
const TaskList = () => {
const [update, setUpdate] = useState<string>('');
useEffect(() => {
TaskStore.fetchTasks();
}, []);
const onChangeValue = (e: any) => {
console.log(e);
setUpdate(e.target.value);
};
return (
<div>
<p>
update input <input onChange={onChangeValue} value={update} />
</p>
{TaskStore.tasks.map((value: any, key) => {
console.log(value);
return (
<div>
<p>
{value.task}
<DeleteTask value={value} taskList={TaskStore} />
<UpdateTask value={update} current={value} taskList={TaskStore} />
</p>
</div>
);
})}
</div>
);
};
export default observer(TaskList);
taskStore.ts:
interface Task {
task: string;
}
class TaskStore {
constructor() {
makeAutoObservable(this);
}
tasks = [] as Task[];
@action fetchTasks = async () => {
try {
const response: any = await axios.get('http://localhost:5000/test');
this.tasks.push(...response.data.recordset);
} catch (error) {
console.error(error);
}
};
}
export default new TaskStore();
CodePudding user response:
This is due to react in development having Strict Mode enabled by default.
https://reactjs.org/docs/strict-mode.html
Which is meant to catch scenarios exactly like this where extra re-renders can cause problems.
To fix this, you should reinitialize the tasks array on every fetch. So something like this.
@action fetchTasks = async () => {
try {
const response: any = await axios.get('http://localhost:5000/test');
this.tasks = response.data.recordset;
} catch (error) {
console.error(error);
}
};
CodePudding user response:
I suspect it duplicates because of this line, in taskStore.ts this.tasks.push(...response.data.recordset);
.
try this.tasks = [...response.data.recordset];
instead.
if the fetch call does not act like infinite scrolling, this approach is the best solution, in my opinion, it won't duplicate the data in dev mode when useEffect
runs twice