Вариант использования:

  • Получить данные из API после первоначального рендеринга
  • Разрешить пользователю устанавливать интервал для повторяющихся вызовов API
  • Извлекать данные из API с заданной частотой

Фрагмент кода

Объяснение

Этап 1: после первоначального рендеринга…

useEffect (строка 23) выполняет и извлекает данные из конечной точки. Если ответ будет успешным, он обновит состояние, используя setData (строка 25). Затем div (строка 45) будет повторно отображаться, так как данные, которые он отображает, изменились.

23|  useEffect(() => {
24|    fetch("api/data")
25|      .then((res) => setData(res))
26|      .catch((err) => console.warn(err));
...
45|      {data.map(({ id, value }) => <div key={id}>{value}</div>)}

Этап 2: после того, как пользователь выберет вариант, 5 секунд в раскрывающемся списке…

onChange (строка 36) запускается и выполняет setFetchDataInterval (строка 37).

36|        onChange={({ target }) => 
37|          setFetchDataInterval(target.value)}

Этап 3. Когда setFetchDataInterval (строка 8) выполняется…

он проверяет, был ли уже установлен интервал в fetchDataIntervalId.current (строка 10).

8 |  const setFetchDataInterval = (interval) => {
9 |    // Clear old interval
10|    if (fetchDataIntervalId.current) {

Примечание: используйте ссылку

Когда интервал установлен в JavaScript, он возвращает идентификатор, который мы можем использовать для очистки того же интервала. Мы не хотим терять идентификатор интервала между рендерами.

Мы могли бы использовать useState для отслеживания идентификатора интервала между рендерингами, но простое изменение идентификатора интервала НИКОГДА не изменит DOM. Мы это знаем, но React этого не знает. Каждый раз, когда состояние (которое мы используем для хранения идентификатора интервала) изменяется, он по-прежнему создает виртуальный DOM и сравнивает его с фактическим DOM.

Если мы используем useRef, изменение идентификатора интервала не приведет к запуску всех событий, происходящих в useState (даже если нет повторного рендеринга). Мы можем хранить идентификатор интервала в возвращаемом свойстве useRef, current.

6 |  const fetchDataIntervalId = useRef();
...
11|      clearInterval(fetchDataIntervalId.current);
12|      fetchDataIntervalId.current = undefined;
...
17|      fetchDataIntervalId.current = setInterval(() => {
18|        setFetchDataTrigger(Date.now());
19|      }, interval);

Этап 4. Если ранее был установлен интервал…

используйте идентификатор предыдущего интервала, чтобы очистить старый интервал (строка 11). Затем установите для идентификатора интервала значение undefined (строка 12).

11|      clearInterval(fetchDataIntervalId.current);
12|      fetchDataIntervalId.current = undefined;

Этап 5. Затем проверьте новый интервал…

если интервал установлен на 0 или меньше, автоматическое обновление отключено. Мы закончим!

16|    if (interval > 0) {

Если интервал больше 0, мы создадим интервал, используя setInterval (строка 17). Первый параметр — это функция, которую мы хотим выполнять с частотой, а второй параметр — время в миллисекундах (5 секунд == 5000). Функция setInterval вернет идентификатор, который мы сохраним в fetchDataIntervalId.current (строка 17).

17|      fetchDataIntervalId.current = setInterval(() => {
18|        setFetchDataTrigger(Date.now());
19|      }, interval);

Теперь давайте посмотрим на функцию, которую мы передали в качестве первого параметра в setInterval. С интервалом выполняется setFetchDataTrigger. Все, что он делает, это устанавливает fetchDataTrigger с текущим временем (строка 18). Какой в ​​этом смысл?

Взгляните на массив переменных, переданных в useEffect в качестве второго параметра (строка 30). fetchDataTrigger находится в этом массиве! Это означает, что при изменении fetchDataTrigger он выполнит useEffect (строка 23) и снова извлечет данные, как на этапе 1.

23|  useEffect(() => {
...
30|  }, [fetchDataTrigger]);

Хорошо, но зачем устанавливать время? Это просто простой способ гарантировать, что когда setFetchDataTrigger выполняется с интервалом, новое значение fetchDataTrigger всегда отличается и запускает useEffect.

Date.now() will return a different value 5 seconds in the future.

Этап 6. Учет интервальной очистки при размонтировании…

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

23|  useEffect(() => {
...
28|    // Clean up for unmount to prevent memory leak
29|    return () => clearInterval(fetchDataIntervalId.current);

Этап 7. Наслаждайтесь автоматической загрузкой с определенным интервалом!