Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic list of todos #2758

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Conversation

yzhyhaliuk
Copy link

@yzhyhaliuk yzhyhaliuk commented Feb 4, 2025

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your hard work on this pull request! 😊 While your implementation meets many of the task requirements, there are a few critical issues that need to be addressed before we can approve it:

  1. State Initialization with Props: Initializing state directly from props can lead to unexpected behavior. Please ensure that state is not initialized from props in the TodoList.tsx file.

  2. Dependency Arrays in useEffect: Ensure that dependencies in useEffect hooks are stable to avoid unnecessary re-renders or API calls. This includes stabilizing functions like onFilterActive, onFilterAll, and onFilterCompleted using useCallback.

  3. Handling selectedId: Using 0 as an initial value for selectedId can cause issues if a todo with an ID of 0 exists. Consider using null to indicate no selection, and adjust your logic accordingly.

  4. Conditional Rendering and Classnames: Ensure that elements are conditionally rendered only when data is fully available, and consider using conditional classnames to improve user experience, such as visually indicating the selected todo.

These changes are important to ensure the robustness and clarity of your code. Once these issues are addressed, your pull request will be ready for approval. Keep up the great work! 🌟

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

🔄 Fix the issues, commit the changes, and then re-request my review using the Re-request review button in the Reviewers tab.

src/App.tsx Outdated
const [allTodos, setAllTodos] = useState<Todo[]>([]);
const [todos, setTodos] = useState<Todo[]>([]);
const [loading, setLoading] = useState(false);
const [selectedId, setSelectedId] = useState(0);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider initializing selectedId with null instead of 0 to clearly indicate that no todo is selected initially. This will also help in avoiding potential confusion with a todo having an ID of 0.

</div>
</div>
</div>
</div>

<TodoModal />
{selectedId && (

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using selectedId directly in a boolean context may lead to unexpected behavior if a todo with an ID of 0 exists. Consider checking for selectedId !== 0 or using a more explicit condition.

onFilterCompleted,
onFilterByTitle,
}) => {
const [isQuery, setIsQuery] = useState(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isQuery state is used to determine if there is a query present. However, since query.length > 0 can be directly checked where needed, you might consider removing isQuery to simplify the state management.

break;
}
}
}, [query, filterStatus, onFilterActive, onFilterAll, onFilterCompleted]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency array for useEffect includes onFilterActive, onFilterAll, and onFilterCompleted. Ensure these functions are stable (e.g., wrapped in useCallback) to prevent unnecessary re-renders.

);
<tbody>
{todos.map(todo => (
<tr data-cy="todo" key={todo.id} className="">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a conditional class to the <tr> element to visually indicate the selected todo. This can improve the user experience by clearly showing which todo is currently selected.

data-cy="selectButton"
className="button"
type="button"
onClick={() => handleSelect(todo.id)}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handleSelect function is straightforward, but you might consider inlining this logic directly in the onClick handler if it remains simple. This can reduce the number of function declarations and slightly improve readability.

setLoading(false);
});
}
}, [selectedTodo?.userId, selectedTodo]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency array for useEffect includes selectedTodo?.userId and selectedTodo. Ensure that selectedTodo is stable or derived from a stable source to prevent unnecessary API calls. Consider using id as a dependency instead, since it directly determines the selected todo.

type="button"
className="delete"
data-cy="modal-close"
onClick={() => onClose(0)}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When closing the modal, consider passing null or undefined to onClose instead of 0 to clearly indicate that no todo is selected. This aligns with the suggestion to initialize selectedId with null in the App.tsx file.


{' by '}

<a href="mailto:[email protected]">Leanne Graham</a>
<a href={`mailto: ${data?.email}`}>{data?.name}</a>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that data?.email and data?.name are available before rendering the link. You might want to conditionally render this part to avoid displaying an incomplete link if the data is not yet loaded.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Your work on the project has been reviewed, and I'm pleased to say that it meets the requirements! 🎉

You've effectively addressed the previous issues, particularly with the initialization of selectedId and the use of useCallback to stabilize functions. The components are well-structured, and the use of useEffect is appropriate with stable dependencies. The conditional rendering and use of classnames are implemented correctly, enhancing the user interface.

However, there are a few points to keep in mind for future improvements:

  • Dependency Arrays in useEffect: Ensure that all dependencies in your useEffect hooks are necessary to avoid unnecessary re-renders or re-fetching of data. This is crucial for maintaining performance and ensuring that your application behaves as expected.

  • Conditional Rendering: Make sure that the logic for rendering components like TodoModal aligns with your application's requirements, especially when dealing with values like 0 or null.

  • Function Handling: Verify that functions like onSelect and onClose are correctly updating the state in the parent component to maintain the intended flow of data.

Your attention to these details will help you refine your skills and produce even more robust code in the future. Keep up the great work, and continue learning from each project! 🚀

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

const [filteredTodos, setFilteredTodos] = useState<Todo[]>([]);
const [todos, setTodos] = useState<Todo[]>([]);
const [loading, setLoading] = useState(false);
const [selectedId, setSelectedId] = useState<number | null>(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job on using null as the initial value for selectedId. This helps avoid potential issues with a todo having an ID of 0.

setTodos(todosFromServer);
setLoading(false);
});
}, []);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency array for useEffect is empty, which means this effect will only run once when the component mounts. Ensure this is the intended behavior, as it will not re-fetch todos if any dependencies change.

</div>
</div>
</div>
</div>

<TodoModal />
{selectedId && (

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the conditional rendering of TodoModal aligns with your application's logic. Currently, it renders when selectedId is truthy, which means it won't render if selectedId is 0 or null. This is fine if null is intended to represent no selection.

onFilterActive,
onFilterCompleted,
onFilterByTitle,
]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useEffect hook has a comprehensive dependency array, which is good for ensuring that the effect runs when any of these dependencies change. Make sure that all dependencies are necessary to avoid unnecessary re-renders. In this case, it seems appropriate as each dependency is related to the filtering logic.

data-cy="todo"
key={todo.id}
className={classNames({
'has-background-info-light': selectedId === todo.id,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of classNames to conditionally apply the has-background-info-light class based on selectedId is correct. This helps visually indicate the selected todo.

data-cy="selectButton"
className="button"
type="button"
onClick={() => onSelect(todo.id)}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the onSelect function is correctly updating the selectedId in the parent component. This line correctly calls onSelect with the todo.id when the button is clicked.

setLoading(false);
});
}
}, [selectedTodo?.userId, selectedTodo]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useEffect hook includes selectedTodo?.userId and selectedTodo as dependencies. Ensure that these dependencies are necessary to avoid unnecessary re-fetching of user data. In this case, it seems appropriate as it ensures data is fetched when the selected todo changes.

type="button"
className="delete"
data-cy="modal-close"
onClick={() => onClose(null)}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onClose function is correctly called with null to reset the selection when the modal is closed. Ensure that this logic is correctly handled in the parent component.

Copy link

@anastasiiavorobiova anastasiiavorobiova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Almost done

src/App.tsx Outdated
const completedTodos = allTodos.filter(todo => todo.completed);

setFilteredTodos(completedTodos);
setTodos(completedTodos);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's enough to have one state for filtered todos

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, but If I remove filteredTodos, the search through the input field always works on all todos, even if I initially selected "Active" or "Completed". And If I use todos instead of filteredTodos, then when I delete a few letters to modify the search, the list is no longer filtered.

}

useEffect(() => {
if (filterStatus === 'all') {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using an enum for this

Copy link

@volodymyr-soltys97 volodymyr-soltys97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job 👍
Let's improve your code

src/App.tsx Outdated
Comment on lines 14 to 15
const [allTodos, setAllTodos] = useState<Todo[]>([]);
const [filteredTodos, setFilteredTodos] = useState<Todo[]>([]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant states

Suggested change
const [allTodos, setAllTodos] = useState<Todo[]>([]);
const [filteredTodos, setFilteredTodos] = useState<Todo[]>([]);

src/App.tsx Outdated
Comment on lines 22 to 27
getTodos().then(todosFromServer => {
setAllTodos(todosFromServer);
setFilteredTodos(todosFromServer);
setTodos(todosFromServer);
setLoading(false);
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
getTodos().then(todosFromServer => {
setAllTodos(todosFromServer);
setFilteredTodos(todosFromServer);
setTodos(todosFromServer);
setLoading(false);
});
getTodos()
.then(setTodos)
.finally(() => setLoading(false));

Comment on lines 10 to 14
enum FilterStatus {
All = 'all',
Active = 'active',
Completed = 'completed',
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move enum to the separate file

Comment on lines 29 to 33
<tr
data-cy="todo"
key={todo.id}
className={classNames({
'has-background-info-light': selectedId === todo.id,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this logic to the PostItem component

'has-text-danger': !todo.completed,
})}
>
{todo.title}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use destructuring for todo

Copy link

@volodymyr-soltys97 volodymyr-soltys97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! 🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants