React Hooks - обработка асинхронного вызова API - PullRequest
2 голосов
/ 18 октября 2019

Я пытаюсь настроить пользовательский хук, чтобы обрабатывать все api-выборки в моем проекте. Я могу сделать звонок успешно и сохранить данные, но только по звонкам после первого. Я вполне уверен, что первый звонок ничего не возвращает из-за условий гонки и характера асинхронности.

Вот мой хук:

import { useState, useEffect } from 'react'
import api from 'services/api'

const useHopServiceApi = () => {
    const [data, setData] = useState([])
    const [url, setUrl] = useState('')
    const [body, setBody] = useState({})
    const [isLoading, setIsLoading] = useState(false)
    const [isError, setIsError] = useState(false)

    useEffect(() => {
        const fetchData = async () => {
            setIsError(false)
            setIsLoading(true)
            try {
                const result = await api.post(url, body)
                setData(result.d)
            } catch (error) {
                setIsError(true)
            }
            setIsLoading(false)
        }
        if (url && body) {
            fetchData()
        }
    }, [url, body])
    return [{ data, isLoading, isError }, setUrl, setBody]
}

export default useHopServiceApi

и компонент, в который он вызывается:

const HomePage = (props) => {
  const [{ data, isLoading, isError }, doFetch, setBody] = useHopServiceApi()

const handleClickSelectInterests = () => {
    setBody({ count: 1 })
    doFetch('/GetPopularCities')
    console.log('data:', data)
  }
}

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

Ответы [ 2 ]

0 голосов
/ 19 октября 2019

Из документов :

Функция setState используется для обновления состояния. Он принимает новое значение состояния и ставит в очередь повторную визуализацию компонента.

При первом щелчке обновления хуков: enqued и console.log ('data:', data) достигается перед выполнением обновлений состояния, поэтому в журнал заносятся пустые данные.

Вы должны поместить console.log в другие места функции, чтобы лучше понять последовательность выполнения

0 голосов
/ 19 октября 2019

Причина, по которой вы не видите данные после первого щелчка, заключается в том, что у вас еще нет данных из doFetch сразу после их вызова.

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

Вот пример, чтобы показать, что я имею в виду:

Пример песочницы кода

Корневой компонент:

import React from "react";
import ReactDOM from "react-dom";

import useHopServiceApi from "./useHopServiceApi";
import "./styles.css";

function App() {
  const [{ data, isLoading, isError }, doFetch] = useHopServiceApi();
  console.log("Data in render!", data);
  const handleClick = () => {
    doFetch("/fakeUrl");
    // Data logged below will show the data from the previous request, not the latest
    console.log("Data in handle click!", data);
  };
  return (
    <div className="App">
      {isLoading && <div>Is loading!</div>}
      <button onClick={handleClick}>Simulate fetch!</button>
      {data && <div>Data! {data}</div>}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

ВашКрюк:

import { useState, useEffect } from "react";
let numClick = 1;

const simulatedFetch = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`Fetch request data for request number ${numClick}`);
      numClick++;
    }, 2000);
  });
};
const useHopServiceApi = () => {
  const [data, setData] = useState([]);
  const [url, setUrl] = useState("");
  const [body, setBody] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsError(false);
      setIsLoading(true);
      try {
        const result = await simulatedFetch();
        console.log("new result!", result);
        setData(result);
        setUrl("");
      } catch (error) {
        setIsError(true);
      }
      setIsLoading(false);
    };
    if (url) {
      fetchData();
    }
  }, [url, body]);
  return [{ data, isLoading, isError }, setUrl, setBody];
};

export default useHopServiceApi;

Приведенный выше пример показывает, что вы можете использовать самые последние данные в функции рендеринга, даже если вы не можете войти в них в handleClick функции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...