Функция useState () в ответ не обновляет данные - это проблема sort ()? - PullRequest
1 голос
/ 23 марта 2020

Когда я нажимаю на кнопку, чтобы отсортировать данные о странах после загрузки веб-сайта, данные отображаются корректно. Но когда я хочу снова отсортировать его по другому значению, данные не обновляются и состояние также не обновляется, однако функция работает хорошо, так как я вижу, что результаты в консоли отсортированы правильно. В чем может быть причина этого странного поведения? Спасибо за ваше время.

 function AllCountries({ countries }) {
  const [sortedCountries, setSortedCountries] = useState([]);

  useEffect(() => {
      console.log(sortedCountries)
  }, [sortedCountries])

  const sortResults = (val) => {
    let sortedResults = countries.sort((a, b) => {
      if (val === "deaths") {
        return b.TotalDeaths - a.TotalDeaths;
      } else if (val === "cases") {
        return b.TotalConfirmed - a.TotalConfirmed;
      } else if (val === "recovered") {
        return b.TotalRecovered - a.TotalRecovered;
      }
    });
    console.log(sortedResults);
    setSortedCountries(sortedResults);
  };

  return (
    <div className="all-container">
      <p>Sort countries by the highest number of:</p>
      <button onClick={() => sortResults("deaths")}>Deaths</button>
      <button onClick={() => sortResults("cases")}>Cases</button>
      <button onClick={() => sortResults("recovered")}>Recoveries</button>
      <ul className="all-countries">
        {sortedCountries.map((country, key) => {
          return <li key={key}>{country.Country}</li>;
        })}
      </ul>
    </div>
  );
}

export default AllCountries;

Ответы [ 3 ]

3 голосов
/ 23 марта 2020

Array.sort() метод не возвращает новую ссылку, он возвращает ту же ссылку. Поэтому я предполагаю, что в sortedCountries состоянии хранится та же ссылка props.countries, поэтому второе нажатие кнопки не устанавливает состояние (это та же ссылка), я могу дать вам простое решение, просто измените эту строку setSortedCountries(sortedResults) с этим setSortedCountries([...sortedResults]) в этом случае копия sortedResults будет передана в setSortedCountries (новая ссылка).

1 голос
/ 23 марта 2020

let sortedResults = country.sort

эта строка сортирует реквизиты стран и устанавливает sortedResults для этого указателя

Предположим, что указатель содержится в mem | 0001 | для простоты

После первого щелчка функция запускается, пропадает сортировка, и sortedResults устанавливается через setSortedCountries (заданное состояние).

Это запускает рендер, который вы хотите, потому что предыдущее состояние было неопределенным, и теперь оно указывает на | 0001 |

Когда ваша функция запускается снова, функция сортировки запускается, выполняет свою работу на | 0001 | и возвращается - как вы уже догадались - | 0001 | но с вашим новым отсортированным массивом.

Когда вы go устанавливаете состояние во второй раз, фактически никакого состояния не было изменено, потому что предыдущая страна была | 0001 | и страна, которую вы хотите изменить, это | 0001 |

Итак, что мы можем сделать, мой добрый сэр?

Сначала мне нужно, чтобы вы на секунду задумались над проблемой, подумали о том, как вы может решить эту проблему и попытаться применить некоторые изменения.

То, что вы можете попытаться сделать, это скопировать реквизиты стран в новый указатель массива с теми же значениями, а затем отсортировать его, а затем установить состояние sortedCountries в этот список .

Имеет ли это смысл?

Кстати, по тем же причинам, почему, если вы попытаетесь установить setState непосредственно в новом состоянии объекта, новое состояние объекта будет точно равно тот, который вы установили. Здесь нет настоящих магов c. React автоматически не объединяет ваше предыдущее состояние объекта и ваше новое, если вы явно не указали это сделать.

В некотором смысле вы сказали «реагировать», чтобы проверить различия между двумя государствами, старой страной и новым государством страны (за кадром с Vdom), но чтобы реагировать, эти два государства не имеют различий. И поскольку два состояния объекта не имеют различий, фактических изменений DOM не будет.

Если дважды установить указатель, то не произойдет никаких реальных изменений.

Поэтому необходимо установить состояние на фактическое новый указатель с новыми значениями, поэтому реагирующий виртуальный дом может сравнить два состояния (предыдущий список стран) и новый список стран.

Надеюсь, это поможет

-

0 голосов
/ 23 марта 2020

Это небольшая проблема в React, и другое решение заключается в использовании useReducer . такие как ниже:

function reducer(state, action) {
   return [...state, ...action];
}
 function AllCountries({ countries }) {
  const [sortedCountries, setSortedCountries] = useReducer(reducer, []);

  useEffect(() => {
      console.log(sortedCountries)
  }, [sortedCountries])

  const sortResults = (e, val) => {
      e.preventDefault();
    let sortedResults = countries.sort((a, b) => {
      if (val === "deaths") {
        return b.TotalDeaths - a.TotalDeaths;
      } else if (val === "cases") {
        return b.TotalConfirmed - a.TotalConfirmed;
      } else if (val === "recovered") {
        return b.TotalRecovered - a.TotalRecovered;
      }
    });
    console.log(sortedResults);
    setSortedCountries(sortedResults);
  };

  return (
    <div className="all-container">
      <p>Sort countries by the highest number of:</p>
      <button onClick={(e) => sortResults(e, "deaths")}>Deaths</button>
      <button onClick={(e) => sortResults(e, "cases")}>Cases</button>
      <button onClick={(e) => sortResults(e, "recovered")}>Recoveries</button>
      <ul className="all-countries">
        {sortedCountries.map((country, key) => {
          return <li key={key}>{country.Country}</li>;
        })}
      </ul>
    </div>
  );
}

export default AllCountries;
...