Как вызвать useEffect при инициализации без изменения состояния в React?

Я хочу получить список данных и отсортировать его при первой загрузке страницы, а затем я хочу иметь возможность сортировать по (fName) или (lName). Сортировка работает, когда я инициирую изменение состояния, но не при начальной загрузке, она отображается в том порядке, в котором мне ее дает база данных, я хочу инициировать сортировку сразу после загрузки данных.

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

sortByfName() и sortBylName() передаются как обратные вызовы для запуска оттуда.

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

function App() {
  const [contacts, setContacts] = useState([]);
  const [sortBy, setSortBy] = useState('lName');

  // GET DATA FROM SERVER
  useEffect(() => {
    axios
      .get('http://localhost:5000/')
      .then((result) => {
        setContacts(result.data);
      })
      .catch((err) => console.log(err));
  }, []);

  // SORT CONTACTS
  useEffect(() => {
    const sorted = contacts.sort((a, b) => {
      let nameA = a[sortBy].toUpperCase();
      let nameB = b[sortBy].toUpperCase();
      if (nameA < nameB) return -1;
      if (nameA > nameB) return 1;
      return 0;
    });
    setContacts(sorted);
  }, [sortBy, contacts]);

  const sortByfName = () => setSortBy('lName');

  const sortBylName = () => setSortBy('fName');

... A few more functions and then render the JSX

person Joniverse    schedule 31.08.2020    source источник
comment
При первой загрузке, какую сортировку вы хотите сначала lName или fName   -  person Shubham Verma    schedule 31.08.2020
comment
fName Я думаю, но это не имеет большого значения.   -  person Joniverse    schedule 31.08.2020
comment
Затем выполните в своей .then эту логику сортировки и установите setContacts, затем   -  person Shubham Verma    schedule 31.08.2020


Ответы (3)


Прежде всего, было бы лучше передать аргумент сортировки вызову API, это обычная и лучшая практика: http://localhost:5000/?sort=fName

Но если это невозможно, вы должны отсортировать данные сразу после получения ответа.

// GET DATA FROM SERVER
  useEffect(() => {
    axios
      .get('http://localhost:5000/')
      .then((result) => {
        const sortedData = sortHandler(result.data, sortBy);
        setContacts(sortedData);
      })
      .catch((err) => console.log(err));
  }, []);

А также

const sortHandler = (data, sortBy) => {
   return data.sort((a, b) => {
      let nameA = a[sortBy].toUpperCase();
      let nameB = b[sortBy].toUpperCase();
      if (nameA < nameB) return -1;
      if (nameA > nameB) return 1;
      return 0;
    });
}

И дальнейшая сортировка по изменению состояния

// SORT CONTACTS
  useEffect(() => {
    const sorted = sortHandler(contacts, sortBy);
    setContacts(sorted);
  }, [sortBy, contacts]);
person ali eslamifard    schedule 31.08.2020
comment
Мне нравятся лучшие практики, так что спасибо, это решение, которое я выберу! Я новичок в этом, и мне действительно нужно изучить общие закономерности. - person Joniverse; 31.08.2020

Я предлагаю вам выполнить логику сортировки перед установкой состояния contacts при монтировании компонента. См. мой комментарий к обратному вызову .then

// GET DATA FROM SERVER
useEffect(() => {
  axios
    .get('http://localhost:5000/')
    .then((result) => {
      // perform sorting logic here before setting contacts

      setContacts(result.data);
    })
    .catch((err) => console.log(err));
}, []);

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

person 95faf8e76605e973    schedule 31.08.2020
comment
Я попытался переместить сортировку в функцию вне useEffect и просто вызвать ее оттуда, а также перед setContacts(), но я получаю: Функция «sort» заставляет зависимости useEffect Hook (в строке 47) изменяться при каждом рендеринге. Переместите его внутрь обратного вызова useEffect. - person Joniverse; 31.08.2020
comment
вы можете использовать объект result - это то, что вы сортируете. Кроме того, я только что понял, что вы напрямую изменяете состояние contacts через собственный sort, я предлагаю вам сначала клонировать contacts (например, с помощью синтаксиса распространения), а затем отсортировать этот клон - person 95faf8e76605e973; 31.08.2020
comment
Я понимаю, почему напрямую изменять контакты плохо, но почему через синтаксис распространения? Почему бы просто не скопировать контакты в новый объект и не выполнять над ним операции? - person Joniverse; 31.08.2020
comment
Или подождите, я действительно мутирую контакты? Я думал, что только читаю значения из контактов и сохраняю их в отсортированном виде? - person Joniverse; 31.08.2020
comment
sort напрямую сортирует и возвращает массив — он не создает новый массив, например, карта делает - person 95faf8e76605e973; 31.08.2020
comment
Я попробовал спред, но он создает бесконечный цикл, вздох.. useEffect(() => {const sorted = [...contacts].sort((a, b) => { - person Joniverse; 31.08.2020
comment
это потому, что вы устанавливаете состояние контактов внутри useEffect через setContacts(sorted), то есть (1) устанавливаете новые контакты (2) вызываете эффект использования (3) повторяете шаг 1 - person 95faf8e76605e973; 31.08.2020

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

Прежде всего, я сделал начальную сортировку в вызове базы данных. Лучшая практика :-)

Тогда было бы просто глупо использовать sort в useEffect, так как он запускается событием, поэтому я просто сделал обычную функцию для передачи вместе с компонентом с кнопками. Я использовал событие, чтобы получить параметр sortBy.

function App() {
  const [contacts, setContacts] = useState([]);

  // GET DATA FROM SERVER
  useEffect(() => {
    axios
      .get('http://localhost:5000/')
      .then((result) => {
        setContacts(result.data);
      })
      .catch((err) => console.log(err));
  }, []);

  // SORT CONTACTS
  const sort = (event) => {
    event.preventDefault();
    const sortBy = event.target.getAttribute('name');
    const sortContacts = [...contacts];
    sortContacts.sort((a, b) => {
      let nameA = a[sortBy].toUpperCase();
      let nameB = b[sortBy].toUpperCase();
      if (nameA < nameB) return -1;
      if (nameA > nameB) return 1;
      return 0;
    });
    setContacts(sortContacts);
  };

// And so on
person Joniverse    schedule 31.08.2020