Решение нескольких рендеров компонентов, включая useEffect, useState и Axios - PullRequest
1 голос
/ 13 июля 2020

У меня есть функциональный компонент React, который выполняет вызов ax ios, устанавливает его в состояние и будет использовать эти данные при рендеринге.

Текущий код:

WeatherPanel. jsx

import React, { useEffect, useState } from "react";
import getLocationData from "../api/getLocationData";

const WeatherPanel = () => {
  const [locationData, setLocationData] = useState();

  useEffect(() => {
    async function populateLocationData() {
      const data = await getLocationData();
      setLocationData(data);
    }
    populateLocationData();
  }, []);

  return locationData ? (
    <>
      <div>Hello {locationData.woeid}</div>
    </>
  ) : (
    <>Loading</>
  );
};

export default WeatherPanel;

getLocationData. js

import axios from "axios";

const getLocationData = async () => {
  const response = await axios.get("/api/location/44418/");
  return response.data;
};

export default getLocationData;

Вопрос:

Похоже, мне нужно иметь защиту locationData ? ( на рендере, и поэтому часть загрузки, поскольку без нее она пытается отрендерить до того, как useState внутри useEffect завершится, в результате чего locationData.woeid будет неопределенным и сломается.

Это правильный / лучший способ справиться с этим? Есть ли способ для функционального компонента завершить что-то перед попыткой первого рендеринга?

(я знаю, что <>Loading</> следует заменить экраном загрузки или счетчиком или чем-то еще, больше спрашивая о структуре кода) .

Спасибо!

1 Ответ

1 голос
/ 13 июля 2020

Вы можете сохранить состояние загрузки и работать с ним следующим образом:

import React, { useEffect, useState } from 'react';
import getLocationData from '../api/getLocationData';

const WeatherPanel = () => {
  const [locationData, setLocationData] = useState();
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    async function populateLocationData() {
      setIsLoading(true);
      try {
        const data = await getLocationData();
        setLocationData(data);
        setIsLoading(false);
      } catch (error) {
        console.log(error);
        setIsLoading(false);
      }
    }
    populateLocationData();
  }, []);

  function renderWeahter() {
    if (isLoading) return <div>Loading...</div>;
    return <div>Hello {locationData.woeid}</div>;
  }

  return <div>{renderWeahter()}</div>;
};

export default WeatherPanel;
...