Как говорят люди: «Это глупо, если это не работает».
Основы, которые вы можете не знать
Во-первых, инициализация
Принято инициализировать состояние как:
const [state, setState] = useState();
Но… useState
— это просто функция, которая возвращает массив, и вы можете сбрасывать его куда угодно, если не нарушаете правило крючков.
И пока мы здесь, вы можете инициализировать его функцией, эта функция будет выполняться только один раз, независимо ни от чего, и все.
Второй момент, что может быть состоянием.
ЛЮБОЕ! (насколько я знаю =p)
Как насчет promise
тогда? Да, вы можете иметь обещания в состоянии, конечно, что вы не можете распаковать их внутри JSX части.
Первая версия
Имея это в виду, вы, вероятно, думаете о чем-то подобном:
function FirstVersion() {
const [state, setState] = useState(() =>
fakeFetch("First Version!")
.then((val) => setState(val))
.catch((err) => setState(err))
);
return (
<div style={{ marginTop: "2em" }}>
{
(state instanceof Promise)
? "Loading First Version Component..."
: state
}
</div>
);
}
И это будет работать!
useStatePromise
Итак, я поигрался и сделал этот пользовательский хук:
import { useEffect, useState } from "react";
export function useStatePromise(promise) {
const [error, setError] = useState(null);
const [value, setValue] = useState(() => {
promise
.then((val) => setValue(val))
.catch(setError);
});
const [newValue, setNewValue] = useState(null);
useEffect(() => {
if (newValue instanceof Promise) {
newValue.then(setValue).catch(setError);
} else {
setValue(newValue);
}
}, [newValue, setValue]);
return [value, setNewValue, error];
}
Добавляя к тому, что я сделал в первой версии, сначала я извлек это в пользовательский хук, затем я добавил способ изменить состояние, это делается путем использования другого состояния для сохранения обещания до завершения.
Пример проекта
См. в CodeSandbox
Бонус — useRefPromise
Поскольку я был там, я также поиграл с useRef
.
import { useRef } from "react";
export function useRefPromise(promise) {
const ref = useRef(promise.then((val) => (ref.current = val)));
if (ref.current instanceof Promise) {
return null;
}
return ref.current;
}
Если вы открыли пример, вы увидите, что он работает… но будьте осторожны!
Это работает только потому, что useEffect
продолжает заставлять рендеры, которые заставят его подхватить последние значения ref. Так что… в нескольких сценариях это сработает.
Закомментируйте useEffect
с setInterval
и посмотрите, как это будет работать.
Outro
Функции React — это просто функции. Да, в фоновом режиме происходит много чего, но, насколько вы понимаете, это функции, и поэтому вы можете делать с ними всякие безумные вещи.
Но опять же, все это, вероятно, плохие идеи, которые не стоит использовать, если только у вас нет дела, которому это каким-то образом поможет.
Cover Photo by Womanizer Toys on Unsplash