Памятка React Use не обновляется

У меня есть список дел. Я переместил заметку об использовании todolist, чтобы она обновлялась только при добавлении todo, но пользовательский интерфейс, похоже, не отражает

import "./styles.css";
import React from "react";

export default function App() {
  return (
    <div className = "App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <TodoList />
    </div>
  );
}

const Todo = ({ taskName }) => {
  console.info("in here todo");
  return <div>{taskName}</div>;
};

const TodoList = () => {
  const [todoList, setTodoList] = React.useState([]);
  const [iptValue, setIptValue] = React.useState("");
  const todoWrapper = React.useMemo(() => {
    return (
      <>
        {(todoList || []).map((item) => (
          <Todo taskName = {item} key = {item} />
        ))}
      </>
    );
  }, [todoList]);
  return (
    <div>
      {todoWrapper}
      <input
        type = "text"
        onChange = {(ev) => {
          setIptValue(ev.target.value);
        }}
      />
      <button
        onClick = {() => {
          const todoArr = todoList;
          todoArr.push(iptValue);
          setIptValue("");
          setTodoList(todoArr);
        }}
      >
        Add Notes
      </button>
    </div>
  );
};

ссылка на codepen: https://codesandbox.io/s/stoic-cloud-phuxsk?file=/src/App.js:0-1082

Вызов setTodoList(todoArr); с тем же массивом с точки зрения reference не вызовет повторную визуализацию. Вам нужно заменить const todoArr = todoList; на const todoArr = [...todoList];.

Sergey Sosunov 19.04.2023 23:19
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
1
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

useMemo React делает поверхностное сравнение через Object.is

Согласно документации React для useMemo,

React будет сравнивать каждую зависимость с ее предыдущим значением, используя сравнение Object.is.

И, согласно веб-документам MDN для Object.is, он определяет, совпадают ли его аргументы. Одно из правил заключается в том, что если «оба являются одним и тем же объектом (что означает, что оба значения ссылаются на один и тот же объект в памяти)», то объект является одним и тем же.

В вашем коде вы вызываете setTodoList(todoArr), а todoArr является ссылкой на todoList. Единственное изменение, которое вы вносите в todoArr, — это вызов todoArr.push. Однако это не создает новую ссылку в памяти. Это просто изменяет todoList и todoArr, потому что они одно и то же.

Создать новый массив

Что вам нужно сделать, это создать новый массив, а затем вызвать setTodoList. Вы также можете использовать библиотеку, такую ​​​​как Immer или Immutable.js, чтобы позволить вам «модифицировать» массивы и объекты и вместо этого получить новую копию.

// Native react solution
<button
  onClick = {() => {
    const todoArr = [...todoList, iptValue]; // Makes a new copy of the array and appends iptValue
    setTodoList(todoArr);
    setIptValue("");
  }}
>
  Add Notes
</button>

Это может быть не связано, но я просто заметил, что шаблон обновления также неверен, когда новое состояние основано/связано с его исходным значением, оно должно быть установлено через функцию обратного вызова:

// onClick
() => {
    setIptValue("");
    setTodoList((todoList) => {
        const todoArr = [...todoList];
        todoArr.push(iptValue);
        return todoList
    })
}

Я бы не сказал, что схема обновления неверна. Хотя вы можете использовать обратный вызов, как показано в документации React, на которую вы ссылаетесь. В документации явно упоминается обстоятельство, когда вы хотите обновить одну часть состояния несколько раз. У них также есть целая страница на эту тему: react.dev/learn/queueing-a-series-of-state-updates

Andria 24.04.2023 22:35

Другие вопросы по теме