React - загрузка данных перед рендерингом - PullRequest
1 голос
/ 02 октября 2019

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

class MyClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      activeIndex: 0,
      items: []
    }
  }

  componentDidMount() {
    axios
      .get(`API_ADDRESS`, {
        headers: {
          Authorization: `Token XXX`,
        },
      })
      .then(function(response) {
        this.setState({
          items: response.results,
        })
      })
      .catch(error => {
        notification.warning({
          message: error.code,
          description: error.message,
        })
      })
  }

  changeDialog = (e, index) => {
    e.preventDefault()
    this.setState({
      activeIndex: index,
    })
  }

  render() {
    const { activeIndex, items } = this.state
    const {
      first_name: firstName,
      last_name: lastName,
      phone,
      email,
      address,
    } = items[activeIndex]

Ошибка указывает:

Ошибка типа: _items $ activeInde не определена

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

Большое спасибо, Элиотт

Ответы [ 4 ]

1 голос
/ 02 октября 2019

Поскольку API, который вы выбираете с сервера, - async . При первом отображении компонента, данные, которые вы setState в axios , еще не обновили, они просто обновляются, когда компонент выполняет повторное отображение во второй раз.

Таким образом, вы должны проверить состояние в компоненте рендеринга следующим образом, чтобы убедиться, что если activeIndex is defined, то объявите переменную с items[activeIndex]:

activeIndex && const {
      first_name: firstName,
      last_name: lastName,
      phone,
      email,
      address,
} = items[activeIndex]

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

Два вопроса:

  • Остерегайтесь this внутри Promise, возвращенного axios. Вы используете function(){}, поэтому this внутри не является экземпляром компонента. Измените его на функцию стрелки.
  • добавьте охрану, чтобы вы не деструктурировали undefined, когда activeIndex указывает на элемент item, которого там нет (что происходит при начальной загрузке перед аксиосом). извлекает данные).

Исправлено:

// ... (code not shown remains unmodified)
componentDidMount() {
  axios
    .get(`API_ADDRESS`, {
      headers: {
        Authorization: `Token XXX`,
      },
    })
    .then(response => {                                             // changed this line
      this.setState({
        items: response.results,
      })
    })
// ... (code not shown remains unmodified)

render() {
  const { activeIndex, items } = this.state
  if (!items[activeIndex]) {                                        // added this line
    return <div>Hold tight while items are being fetched...</div>;  // added this line
  }                                                                 // added this line
  const {
    first_name: firstName,
// ... (code not shown remains unmodified)
0 голосов
/ 02 октября 2019

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

  constructor(props) {
    super(props)
    this.state = {
      activeIndex: 0,
      items: [],
      isFetching: false
    }
  }

  componentDidMount() {
    // staring your fetching
    this.setState({isFetching: true});
    axios
      .get(`API_ADDRESS`, {
        headers: {
          Authorization: `Token XXX`,
        },
      })
      .then(function(response) {
        // finish fetching when your response is ready :)
        this.setState({
          items: response.results,
          isFetching: false
        });
      })
      .catch(error => {
        // finish fetchnig
        this.setState({isFetching: false})
        notification.warning({
          message: error.code,
          description: error.message,
        })
      })
  }

  changeDialog = (e, index) => {
    e.preventDefault()
    this.setState({
      activeIndex: index,
    })
  }

  render() {

    // if your component is while fetching shows a loading to the user
    if(this.state.isFetching) return <div>Loading...</div>;
    // if there is no results shows a msg to the user
    if(this.state.items.length === 0) return <div>there is not items!!!</div>

    const { activeIndex, items } = this.state
    const {
      first_name: firstName,
      last_name: lastName,
      phone,
      email,
      address,
    } = items[activeIndex]
0 голосов
/ 02 октября 2019

componentDidMount вызывается после того, как render функция вызывается впервые. Поэтому, когда функция render вызывается впервые, запрос HTTP еще не был сделан.

Чтобы решить эту проблему, вы можете проверить внутри функции render, определено activeIndex или нет. Если он не определен, вы можете отобразить какой-нибудь загрузочный счетчик или что угодно.

render() {
    if (!this.state.activeIndex) {
        // show loading spinner
    } else {
        // do your work
    }
}
...