Вопрос об изменении состояния очереди с помощью крючков в React

#javascript #reactjs #react-hooks #use-state

Вопрос:

Итак, я начал изучать React, выполняя компоненты класса. Там, насколько я понимал, что я делаю, если бы у меня был

 this.state = {  isLoading: false,  dataToRender: [], }  this.setState({ isLoading: true }, async () =gt; {  const data = await fetchData();  this.setState({ dataToRender: data , isLoading: false }); })  const message =gt; lt;pgt;loading...lt;/pgt;  if (isLoading) return message();  return (  dataToRender.map )   

для отображения сообщения «загрузка» всякий раз, когда я вызываю API для получения новых данных, я мог бы знать, что «очередь» setState будет выполняться в определенном порядке. Внешнее состояние набора получит первое изменение состояния для первого параметра и функцию, которая будет выполняться сразу после него в качестве второго параметра.

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

 const [isLoading, setIsLoading] = useState(false); const [data, setData] = useState([]);  setLoading(async () =gt; {  setLoading(true)  const data = await fetchData()  setData(data);  return false; })   

это бы не сработало, верно? Я чувствую, что общая логика построения такого рода компонентной логики может отличаться при использовании крючков каким-то образом… Если бы кто-нибудь мог хотя бы указать мне направление, было бы неплохо. Спасибо! 🙂

Ответ №1:

Функции, переданные как useState функция обновления состояния, обрабатываются как синхронные функции, поэтому вы эффективно сохраняете неявно возвращенный объект Promise в состояние.

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

 const [isLoading, setIsLoading] = useState(false); const [data, setData] = useState([]);  const asyncCall = async () =gt; {  setLoading(true);  try {  const data = await fetchData();  setData(data);  } catch(error) {  // handle any errors, logging, etc...  } finally {  setLoading(false);  } };  

Это вызовет/поставит в очередь каждое обновление состояния в том порядке, в котором они поставлены в очередь. Вы также должны окружить любую асинхронную логику в try/catch блоке, чтобы вы могли обрабатывать любые отклоненные обещания, очистить состояние загрузки в a finally , чтобы, независимо от разрешенных/отклоненных обещаний, по завершении кода он сбрасывал состояние загрузки.

Комментарии:

1. Вау, это круто. Так чисто! Спасибо!

2. Привет, Дрю. Что касается вашего редактирования, в моем примере я посчитал, что блок try/catch был неявным в fetchData (), но это решение с finally интересно. Вопрос в следующем: какие ошибки могут возникнуть в setData? Я имею в виду, что как только я обработал ошибку в fetchData(), что может привести к (ошибке)?

3. @Zigoni О, я понимаю. Я занимался только синтаксисом, так fetchData как возвращает обещание, которого вы ждете, технически оно может вернуть отклоненное обещание. Я не думаю, что из функции обновления состояния React будут выдаваться какие-либо ошибки.

4. На самом деле я рассматривал возможность возврата самой стоимости. Я должен признать, что я новичок и все же мало что знаю об обработке ошибок… Я предположил, что функция fetchData() будет содержать весь блок try/catch. Очень признателен, чувак!

Ответ №2:

Там нет обратного вызова с функцией отправки useState .

 const fn = async () =gt; {  setIsLoading(true)  const data = await fetchData()  setData(data)  setIsLoading(false)  })   

Вышеуказанная функция обычно вызывается при таком событии, как onClick или useEffect .

Комментарии:

1. Значит, функции набора состояния пользователя не выполняются асинхронно? Например, могу ли я быть уверен, что данные будут сохранены до того, как загрузка возобновится в false? (кстати, спасибо за ответ!)

Ответ №3:

в зависимости от того, как обычно реагирует на эти вызовы, вы получаете только один повторный рендеринг, но он не может сделать это в асинхронном обратном вызове (например, наши обработчики обещаний успеха и ошибок). Вы можете использовать объект для значения useState или использовать useReducer.

 const [state,setState]=useState({isLoading:false,success:false,isError:false,data:[]})  

затем установите эти свойства для каждого статуса.