Реагировать: useEffect обновляет состояние, но не повторно отображает представление - PullRequest
0 голосов
/ 03 августа 2020

Я хотел бы отсортировать массив объектов. Но я застрял здесь на какое-то время: когда props filterActivated изменяется, состояние обновляется (проверяется в браузере в инструменте react dev), но повторного рендеринга нет.

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

Это мой компонент:

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

// Components
import Idea from './Idea'

const IdeasContainer = ({ filterActivated }) => {

    const [ideasArray, setIdeasArray] = useState([]);

    useEffect(() => {
        const getIdeas = async () => {
            try {
                const response = await fetch("http://localhost:3004/api/ideas")
                const data = await response.json()
                setIdeasArray(data)
            } catch (err) {
                console.error('getIdeas error: ', err, err.stack)
            }
        }
        getIdeas();
    }, []);

    useEffect(() => {
        const sorted = (array) => {
            let newArray = array.sort(function (a, b) {
                if (filterActivated === 'scoreAsc') {
                    return a.score - b.score
                }
                else if (filterActivated === 'scoreDesc') {
                    return b.score - a.score
                }
            });
            setIdeasArray(newArray);
        }
        sorted(ideasArray);
    }, [filterActivated, ideasArray]);

    return (
        <div className="ideasContainer">
            {
                ideasArray.map((idea, index) => {
                    return <Idea key={index} dataIdea={idea} />
                })
            }
        </div>
    )
}

export default IdeasContainer;

1 Ответ

0 голосов
/ 04 августа 2020

Во-первых, у вашего useEffect есть несколько проблем:

Не ссылайтесь на ideaArray как на зависимость useEffect, если вы устанавливаете это значение внутри useEffect. Это вызовет бесконечные циклы, потому что, когда вы устанавливаете значение, снова вызывается `useEffect ', который устанавливает значение, который вызывает его снова, который устанавливает значение ... и так далее. Если вы полагаетесь на предыдущее значение, чтобы установить новое значение, передайте функцию установки функции setIdeasArray, например:

useEffect(() => {
  setIdeasArray(oldValue =>
    [...oldValue].sort((a, b) => {
      if (filterActivated === "scoreAsc") {
        return a.score - b.score;
      } else if (filterActivated === "scoreDesc") {
        return b.score - a.score;
      }
    })
  );
}, [filterActivated]);

Обратите внимание, как я также передаю oldValue в новый массив перед сортировка. Это связано с тем, что Array.sort не является надежно неизменяемым, поэтому в определенных ситуациях он изменяет исходные данные, что нам не нужно в React.

Если состояние меняется, всегда происходит повторный рендеринг. Цикл рендеринга React не совпадает с изменением DOM, но React по-прежнему будет запускать цикл рендеринга компонента при изменении свойств или состояния.

Проблема, с которой вы столкнулись, связана с использованием index в качестве key за каждую идею. Использование индексов в качестве ключей - действительно плохая идея.

Весь смысл ключей состоит в том, чтобы позволить React идентифицировать элементы в массиве без необходимости их повторного рендеринга, поэтому, используя индексы, вы суть в том, что первый элемент (всегда индекс 0) никогда не меняется. Да, ваше состояние переупорядочено, но React видит, что ключи не изменились, поэтому он не меняет DOM для соответствия.

Ключи должны быть связаны с элементом (например, уникальный идентификатор ), так что React может идентифицировать этот элемент по чему-то, не имеющему отношения к «его положению в массиве».

...