Состояние не обновляется при использовании React Hooks

В настоящее время я играю с новой функцией React Hooks и столкнулся с проблемой, когда состояние функционального компонента не обновляется, хотя я считаю, что все делаю правильно, другая пара глаз на это тестовое приложение будет очень признателен.

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

const TodoList = () => {
  let updatedList = useTodoListState({ 
    title: "task3", completed: false 
  });
const renderList = () => {
  return (
    <div>
      {
        updatedList.map((item) => {
          <React.Fragment key = {item.title}>
            <p>{item.title}</p>
          </React.Fragment>
        })
      }
    </div>
  )
}
return renderList();
}

function useTodoListState(state) {
  const [list, updateList] = useState([
    { title: "task1", completed: false },
    { title: "task2", completed: false }
  ]);
  useEffect(() => {
    updateList([...list, state]);
  })
  return list;
}

export default TodoList;

updateList в функции useEffect useTodoListState должен обновлять переменную списка, чтобы она содержала три фрагмента данных, однако это не так.

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

Ответы 1

У вас есть несколько проблем:

  1. В renderList вы неправильно используете React.Fragment. Его следует использовать для обертывания нескольких узлов DOM, чтобы компонент возвращал только один узел. Вы оборачиваете отдельные элементы абзаца каждый в свой собственный фрагмент.
  2. Что-то должно быть возвращено на каждой итерации map. Это означает, что вам нужно использовать ключевое слово return. (Подробнее о синтаксисе стрелочных функций см. в статье этот вопрос.)
  3. Ваш код будет обновляться бесконечно, потому что useEffect обновляет состояние своего собственного хука. Чтобы исправить это, вам нужно включить массив в качестве второго аргумента в useEffect, который скажет React использовать этот эффект только в том случае, если данный массив изменится.

Вот как это все должно выглядеть (с небольшим переформатированием):

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

const TodoList = () => {
  let updatedList = useTodoListState({
    title: "task3", completed: false
  });

  return (
    <React.Fragment> // #1: use React.Fragment to wrap multiple nodes
      {
        updatedList.map((item) => {
          return <p key = {item.title}>{item.title}</p> // #2: return keyword inside map with braces
        })
      }
    </React.Fragment>
  )
}

function useTodoListState(state) {
  const [list, updateList] = useState([
    { title: "task1", completed: false },
    { title: "task2", completed: false }
  ]);

  useEffect(() => {
    updateList([...list, state]);
  }, [...list]) // #3: include a second argument to limit the effect

  return list;
}

export default TodoList;

Обновлено:
Хотя я проверил, что приведенный выше код работает, в конечном итоге было бы лучше переработать структуру, чтобы удалить updateList из useEffect или внедрить другую переменную для управления обновлением.

будет ли использование [...list] в качестве второго аргумента для useEffect вести себя иначе, чем просто использование [list]?

lecstor 04.03.2019 07:43

@lecstor Да. Второй аргумент должен содержать любые значения из внешней области видимости, которые используются внутри useEffect. Здесь массив списка расширяется, поэтому массив списка в ограничителе эффекта также должен быть расширен.

Adam 04.03.2019 07:51

хм.. Более того, useEffect будет работать только в том случае, если какие-либо значения в этом массиве изменились (кроме первого раза), поэтому я не вижу, какая разница. Если, конечно, вы не изменили список, изменив один из его элементов без изменения фактического объекта списка, что не то, что updateList сделал бы.

lecstor 04.03.2019 08:03

Я согласен с этим, но когда я тестировал это, обновление выполнялось бесконечно без распространения массива.

Adam 04.03.2019 08:06

хм.. понял Warning: The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.codeandbox.io/s/9lw4wo1jqr

lecstor 04.03.2019 08:21

и, да, это убило мои коды и ящик без распространения, но это потому, что list обновляется useEffect, поэтому он продолжает срабатывать. Просто природа тестового приложения неверна.

lecstor 04.03.2019 08:24

@ayaz-uddin, я бы сказал, что для текущей реализации пустой массив следует использовать в качестве второго аргумента для useEffect. (для другой реализации см. codeandbox.io/s/wow5q2k9kk)

lecstor 04.03.2019 08:44

В конечном счете, было бы лучше либо реализовать другую переменную для управления обновлением, либо переработать структуру, чтобы полностью удалить обновление из useEffect.

Adam 04.03.2019 13:54

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