Sobes.tech
Middle+

Look at the code of a React application (Todo list) and fix the problems: API request handling, state management, error handling, adding new tasks, marking tasks as completed.

sobes.tech AI

Answer from AI

In a React Todo List application, the following common problems and their solutions are often encountered:

  1. Handling API requests

    • Use useEffect to load data when the component mounts.
    • Handle errors with try/catch or .catch.
    • Show a loading indicator and error messages.
  2. Working with state

    • Use useState to store the list of tasks.
    • When updating the task list, use the functional setter to avoid issues with asynchronous updates.
  3. Error handling

    • Store error state locally.
    • Show a user-friendly message.
  4. Adding new tasks

    • When adding a new task, update the state by adding the new task to the array.
    • You can optimistically update the UI and then synchronize with the server.
  5. Marking tasks as completed

    • Update the task's completed field in the state.
    • Send an update to the server if necessary.

Example of corrected code:

import React, { useState, useEffect } from 'react';

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [newTask, setNewTask] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchTodos() {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch('/api/todos');
        if (!response.ok) throw new Error('Error loading tasks');
        const data = await response.json();
        setTodos(data);
      } catch (e) {
        setError(e.message);
      } finally {
        setLoading(false);
      }
    }
    fetchTodos();
  }, []);

  const addTask = async () => {
    if (!newTask.trim()) return;
    const task = { id: Date.now(), text: newTask.trim(), completed: false };
    setTodos(prev => [...prev, task]);
    setNewTask('');
    try {
      const response = await fetch('/api/todos', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(task),
      });
      if (!response.ok) throw new Error('Error adding task');
    } catch (e) {
      setError(e.message);
      // You can revert the addition or notify the user
    }
  };

  const toggleCompleted = async (id) => {
    setTodos(prev => prev.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo));
    try {
      const todo = todos.find(t => t.id === id);
      const response = await fetch(`/api/todos/${id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ completed: !todo.completed }),
      });
      if (!response.ok) throw new Error('Error updating task');
    } catch (e) {
      setError(e.message);
      // You can revert the change or notify the user
    }
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p style={{ color: 'red' }}>{error}</p>;

  return (
    <div>
      <input
        value={newTask}
        onChange={e => setNewTask(e.target.value)}
        placeholder="New task"
      />
      <button onClick={addTask}>Add</button>
      <ul>
        {todos.map(todo => (
          <li key={todo.id} onClick={() => toggleCompleted(todo.id)}
              style={{ textDecoration: todo.completed ? 'line-through' : 'none', cursor: 'pointer' }}>
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;
Look at the code of a React application (Todo list)… - sobes.tech