Conversation
src/App.tsx
Outdated
| }, []); | ||
|
|
||
| const filteredTodos = () => { | ||
| let copyTodos = [...todos]; |
There was a problem hiding this comment.
Array.filter() już zwraca nową tablicę. Spread [...todos] jest niepotrzebny.
src/App.tsx
Outdated
| <TodoContext.Provider | ||
| value={{ todos, setTodos, loadingIds, setLoadingIds }} | ||
| > | ||
| <ErrorContext.Provider value={{ ...error, showError, closeError }}> |
There was a problem hiding this comment.
Here ytou have some good tips for context
https://kentcdodds.com/blog/how-to-use-react-context-effectively
src/App.tsx
Outdated
| const filteredTodos = () => { | ||
| let copyTodos = [...todos]; | ||
|
|
||
| switch (filter) { | ||
| case 'Active': | ||
| copyTodos = copyTodos.filter(item => !item.completed); | ||
| break; | ||
| case 'Completed': | ||
| copyTodos = copyTodos.filter(item => item.completed); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| return copyTodos; | ||
| }; |
src/App.tsx
Outdated
| <TodoContext.Provider | ||
| value={{ todos, setTodos, loadingIds, setLoadingIds }} | ||
| > | ||
| <ErrorContext.Provider value={{ ...error, showError, closeError }}> |
There was a problem hiding this comment.
Both contexts create new object on each render
src/components/TodoItem/TodoItem.tsx
Outdated
| @@ -0,0 +1,170 @@ | |||
| import classNames from 'classnames'; | |||
| import { useContext } from 'react'; | |||
There was a problem hiding this comment.
Why are you impolrting in each line from the same module it can be squashed into one line
import { useRef, useEffect, useContext, useState } from 'react';
src/components/TodoItem/TodoItem.tsx
Outdated
| type="checkbox" | ||
| className="todo__status" | ||
| checked={todo.completed} | ||
| onClick={todoCompleteButton} |
There was a problem hiding this comment.
Here it should listen for onChange event. onClick z checked will create React warning about controlled component
src/components/TodoItem/TodoItem.tsx
Outdated
| try { | ||
| if (trimmed.length === 0) { | ||
| inputRef.current?.focus(); | ||
| await deleteTodoFromServer(); |
There was a problem hiding this comment.
In editTodo, you add todo.id to loadingIds and then (if the title is empty) call deleteTodoFromServer(), which also adds the same todo.id to loadingIds. So the same ID gets added twice. Then editTodo removes the ID in its finally, but deleteTodoFromServer also tries to remove it in its own finally- this creates a race condition where one finally can clear the loading state while the other operation is still in progress.
src/components/TodoItem/TodoItem.tsx
Outdated
| return; | ||
| } | ||
|
|
||
| await toggleTodo(todo.id, { title: trimmed }); |
src/components/Footer/Footer.tsx
Outdated
| const completed = todos.filter(todo => todo.completed); | ||
| const completedCount = completed.length; | ||
| const active = todos.filter(todo => !todo.completed); | ||
| const activeCount = active.length; |
There was a problem hiding this comment.
| const completed = todos.filter(todo => todo.completed); | |
| const completedCount = completed.length; | |
| const active = todos.filter(todo => !todo.completed); | |
| const activeCount = active.length; | |
| const activeCount = todos.filter(t => !t.completed).length; | |
| const completedCount = todos.length - activeCount; |
src/components/Footer/Footer.tsx
Outdated
| results.forEach((result, index) => { | ||
| if (result.status === 'fulfilled' && result.value === 1) { | ||
| const todoId = idsToDelete[index]; | ||
|
|
||
| setTodos(prev => prev.filter(todo => todo.id !== todoId)); | ||
| } else { | ||
| showError('Unable to delete a todo'); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Each setTodos call inside the loop is a separate state update. In React 18, batching usually covers updates in event handlers, but in async code (after an await) it isn’t guaranteed. It’s better to collect the results first and then call setTodos once:
const deletedIds = results
.map((r, i) => (r.status === "fulfilled" ? idsToDelete[i] : null))
.filter(Boolean);
setTodos((prev) => prev.filter((t) => !deletedIds.includes(t.id)));
https://HiBlurryface.github.io/react_todo-app-with-api/