React component does not update automatically in UI but only in array
Published: 2023-01-27 16:36:15


I'm a newbie to react and I have a problem. When I try to add a new item to my list, the component updates but "closes", in fact to see the new item added to the list, I have to click again on the categories' list. At that point it updates. I have this problem in both the 'todos' component and the 'subtodos' component but not in categories. 

How can I do?

data: 

```
const datas = [
  {
    categoryTitle: "oggi",
    categoryId: "1",
    todos: [
      {
        todoName: "pulire",
        todoId: "a",
        completed: false,
        subTodos: [
          { subTodoName: "pulire bagno", subTodoId: "a1", completed: false },
          { subTodoName: "pulire cucina", subTodoId: "a2", completed: false },
        ],
      },
      {
        todoName: "cucinare",
        todoId: "b",
        completed: false,
        subTodos: [
          { subTodoName: "cucinare primo", subTodoId: "a3", completed: false },
          {
            subTodoName: "cucinare secondo",
            subTodoId: "a4",
            completed: false,
          },
        ],
      },
    ],
  },

  {
    categoryTitle: "pianificato",
    categoryId: "2",
    todos: [
      {
        todoName: "studiare",
        todoId: "c",
        completed: false,
        subTodos: [
          {
            subTodoName: "studiare geometria",
            subTodoId: "a1",
            completed: false,
          },
          {
            subTodoName: "studiare matematica",
            subTodoId: "a2",
            completed: false,
          },
        ],
      },
      {
        todoName: "spesa",
        todoId: "d",
        completed: false,
        subTodos: [
          { subTodoName: "zucchine", subTodoId: "a3", completed: false },
          { subTodoName: "pasta", subTodoId: "a4", completed: false },
        ],
      },
    ],
  },
];

export default datas;

```

app.js:

```
function App() {
  const [todoDatas, setTodoDatas] = useState(datas);
  const [selectedItem, setSelectedItem] = useState();
  const [todoId, setTodoId] = useState();
  const [selectedTodo, setSelectedTodo] = useState();
  return (
    <DataContext.Provider
      value={{
        todoDatas,
        setTodoDatas,
        selectedItem,
        setSelectedItem,
        todoId,
        setTodoId,
        selectedTodo,
        setSelectedTodo,
      }}
    >
      <ComponentContainer>
        <Categories />
        <Todos />
        <Subtodos />
      </ComponentContainer>
    </DataContext.Provider>
  );
}
```

Categories.js

```
function Categories() {
  const { todoDatas, setTodoDatas, setSelectedItem } = useContext(DataContext);

  const [categoryInput, setcategoryInput] = useState(null);

  const catchCategory = (value) => {
    setcategoryInput(value);
  };
  const resetCategory = () => {
    setcategoryInput("");
  };
  const addCategory = () => {
    if (
      categoryInput !== null &&
      categoryInput !== "" &&
      categoryInput !== undefined
    ) {
      setTodoDatas((prev) => {
        return [
          ...prev,
          {
            categoryTitle: categoryInput,
            categoryId: uniqid(),
            todos: [],
          },
        ];
      });
    }
  };
  return (
    <div className="app_wrap">
      <div className="categories_wrap">
        <h5>jessicamoretti@gmail.com</h5>
        <input type="text" placeholder="search"></input>
        {todoDatas?.map((category) => {
          return (
            <p
              key={category.categoryId}
              id={category.categoryId}
              onClick={() => {
                setSelectedItem(
                  todoDatas.find((cat) => {
                    return cat.categoryId === category.categoryId;
                  })
                );
              }}
            >
              {category.categoryTitle}
            </p>
          );
        })}
        <form
          onClick={(e) => {
            e.preventDefault();
            addCategory();
          }}
        >
          <input
            type="text"
            onChange={(e) => {
              catchCategory(e.target.value);
            }}
          ></input>
          <button onClick={resetCategory}>Nuovo elenco</button>
        </form>
      </div>
    </div>
  );
}
```

Todos.js

```
function Todos() {
  const {
    setSelectedItem,
    selectedItem,
    todoId,
    setTodoId,
    todoDatas,
    setTodoDatas,
  } = useContext(DataContext);
 
  const [todoInput, setTodoInput] = useState();

  const catchTodo = (value) => {
    setTodoInput(value);
  };
  const resetTodo = () => {
    setTodoInput("");
  };
  const addTodo = (obj) => {
    if (todoInput !== null && todoInput !== "" && todoInput !== undefined) {
      setSelectedItem(
        selectedItem?.todos?.push({
          todoName: todoInput,
          todoId: uniqid(),
          completed: false,
          subTodos: [],
        })
      );
    }
  };
  return (
    <div className="todos_subtodos_wrap">
      <div className="todos_wrap">
        {selectedItem?.todos?.map((todo) => {
          return (
            <div className="todo" key={todo.todoId}>
              <p
                id={todo.todoId}
                onClick={() => {
                  setTodoId(todo.todoId);
                }}
              >
                {todo.todoName}
              </p>
              <p>subtodo: 0 of {todo.subTodos?.length} </p>
            </div>
          );
        })}

        <form
          className="todos_form"
          onClick={(e) => {
            e.preventDefault();
            addTodo();
          }}
        >
          <input
            type="text"
            className="todos_input"
            placeholder="add todos"
            onChange={(e) => {
              catchTodo(e.target.value);
            }}
          ></input>
          <button className="add_todos" onClick={resetTodo}>
            add todos
          </button>
        </form>
      </div>
    </div>
  );
}

```

Subtodos.js

```
function Subtodos() {
  const {
    setSelectedItem,
    selectedItem,
    todoId,
    setTodoId,
    selectedTodo,
    setSelectedTodo,
  } = useContext(DataContext);
  const [subTodoInput, setSubTodoInput] = useState();
  const [subTodos, setSubTodos] = useState(selectedTodo);
  let selected = selectedItem?.todos?.find((el) => {
    return el.todoId === todoId;
  });
  console.log(selectedItem, "selected item");
  useEffect(() => {
    setSelectedTodo(selected); // contiene il todo selezionato
  }, [selected, setSelectedTodo]);

  const catchSubTodo = (value) => {
    setSubTodoInput(value);
  };
  const addSub = () => {
    if (
      subTodoInput !== null &&
      subTodoInput !== "" &&
      subTodoInput !== undefined
    ) {
      setSelectedTodo(
        selected?.subTodos?.push({
          subTodoName: subTodoInput,
          subTodoId: uniqid(),
          completed: false,
        })
      );
    }
  };

  return (
    <div>
      <div>
        {selectedTodo?.subTodos?.map((el) => {
          return (
            <div key={el.subTodoId}>
              <p> {el.subTodoName}</p>
            </div>
          );
        })}

        <form
          onClick={(e) => {
            e.preventDefault();
            addSub();
          }}
        >
          <input
            type="text"
            placeholder="+ Aggiungi sottoattività"
            onChange={(e) => {
              e.preventDefault();
              catchSubTodo(e.target.value);
            }}
          ></input>
          <button
            onClick={(e) => {
              e.preventDefault();
            }}
          ></button>
        </form>
      </div>
    </div>
  );
}
```