Реакция: ошибка типа: не удается прочитать свойство ‘body’ null

#reactjs

#reactjs

Вопрос:

Я не понимаю, почему React не создает проблем, когда я проверяю данные перед их выводом, но когда я не использую if / else (но есть данные), React выдает мне эту ошибку: TypeError: не удается прочитать свойство ‘body’ null

 import React, { Component } from 'react';
import axios from 'axios'

class Posts extends Component {
  state = {
    post: null
  }
  
  componentDidMount(){
    const id = this.props.match.params.post_id;
    axios.get('https://jsonplaceholder.typicode.com/posts/'   id)
    .then(res => {
      this.setState({
        post: res.data
      })
    })
  }
  render() {
    const post = (
      <p> {this.state.post.body} </p>
      ) 
      
    return (
      <div>
       <p>{post}</p>
      </div>
    );
  }
}

export default Posts;
 

сравнение с:

 
import React, { Component } from 'react';
import axios from 'axios'

class Posts extends Component {
  state = {
    post: null
  }
  
  componentDidMount(){
    const id = this.props.match.params.post_id;
    axios.get('https://jsonplaceholder.typicode.com/posts/'   id)
    .then(res => {
      this.setState({
        post: res.data
      })
    })
  }
  render() {
    const post = this.state.post ? (
      <p> {this.state.post.body} </p>
      ) : ( <p>Loading post....</p>
      )  

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

export default Posts;
 

Помощь была бы признательна 😉

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

1. Ну, данных нет, пока не завершится вызов Ajax.

2. Я не понимаю времени. Когда я добавляю консоль. журнал для метода render(), а также для метода componentDidMount(), затем также во втором примере, где выполняется проверка данных, сначала выполняется render(), а затем componentDidMount() . Это должно привести к тому, что во втором примере также не будет никаких данных. Но на самом деле выводятся данные.

3. Это (почти) правильно, во втором примере изначально нет никаких данных. Разница в том, что второй пример проверяет эту возможность и показывает сообщение «загрузка …», если нет данных. Время: 1) componentDidMount запускается и запускает вызов Ajax, 2) начальный рендеринг с состоянием по умолчанию, 3) через некоторое время вызов Ajax завершается и изменяет состояние, 4) изменение состояния запускает новый рендеринг с новыми данными из вызова Ajax.

4. Я посмотрел на ваш ответ, но когда я добавляю журнал консоли, вот так: componentDidMount(){ const id = this.props.match.params.post_id; axios.get(‘ jsonplaceholder.typicode.com/posts ‘ id) .затем(res => { this.setState({ post: res.данные }) console.log(‘comp’) }) } render() { const post = this.state.post ? ( <p> {this.state.post.body} </p> ) : ( <p>L.</p> ) ; console.log(‘render’) консоль выдает мне: render, render и comp, в таком порядке. Итак, componentdidmount, похоже, идет последним?

5. Нет. Вызов Ajax завершается последним. У вас есть консоль. войдите в функцию, которая вызывается только после завершения вызова Ajax. Вам нужно прочитать, что такое Ajax и как работают асинхронные функции.

Ответ №1:

Вы инициализировали post значение null, что означает, что оно не содержит никакого значения.

Когда вы пытаетесь получить доступ this.state.post.body , это заставляет программу думать, что внутри есть данные post , которые выглядят как, post = {body: "some data"} .

Но в вашем случае этот body элемент не существует, и вы получаете сообщение TypeError: Cannot read property 'body' of null , в котором простым языком говорится, что объект, который вы пытаетесь прочитать, пуст, поэтому нет значения, имеющего ключ body , и именно поэтому вы получаете эту ошибку.

Во втором случае вы выполняете следующий умный условный рендеринг

 const post = this.state.post ? (
      <p> {this.state.post.body} </p>
      ) : ( <p>Loading post....</p>
      ) 
 
 

что делает это, оно просматривает this.state.post и видит, содержит ли оно какие-либо данные, изначально это null ложное значение, поэтому при первом рендеринге, когда данных нет, значение const post = <p>Loading post....</p> и вы видите <p>Loading post....</p> сначала в течение короткого промежутка времени.

Пока это происходит, метод componentDidMount() жизненного цикла выполняет вызов Axios, и когда он получает данные из предоставленного ему URL-адреса, он обновляет состояние post by

 this.setState({
        post: res.data
      })
 

и когда это состояние обновляется, происходит повторное отображение, и на этот раз this.state.post оно не пустое, теперь оно содержит данные, которые ваш вызов axios получил из URL, и на этот раз при выполнении условного отображения

 const post = this.state.post ? (
      <p> {this.state.post.body} </p>
      ) : ( <p>Loading post....</p>
      ) 
 

const post равно = <p> {this.state.post.body} </p> , потому this.state что больше не является пустым.

Вот что происходит шаг за шагом:

введите описание изображения здесь

Шаг 1: При первом запуске приложения выполняется рендеринг, в этот момент значение this.state.post null равно значению, показанному на рисунке. это шаг, который вы получите TypeError: Cannot read property 'body' of null , потому что, как показано на рисунке, this.state.post имеет значение null в первом цикле рендеринга.

Шаг 2: Теперь выполнение componentDidMount() будет выполнено, изначально мы видим, что перед вызовом Axios значение по this.state.post -прежнему равно null .

Шаг 3: вызов Axios возвращает сообщение с заданного URL-адреса, и сразу после этого он обновляет состояние this.state.post .

Шаг 4: Как this.state.post только он обновляется, выполняется повторный запуск, и мы видим render , что метод запускается, и мы видим данные, сохраненные за this.state.post это время, в отличие null от того, что мы получили на шаге 1.

Я надеюсь, что эта картинка и пошаговая операция помогут вам понять, почему оба приведенных примера ведут себя так, как они ведут.

Вы можете найти этот пример здесь, ознакомьтесь с выводом на консоль: пример Stackblitz

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

1. Я не понимаю времени. Когда я добавляю консоль. журнал для метода render(), а также для метода componentDidMount(), затем также во втором примере, где выполняется проверка данных, сначала выполняется render(), а затем componentDidMount() . Это должно привести к тому, что во втором примере также не будет никаких данных. Но на самом деле выводятся данные.

2. Хорошо, теперь я понимаю проблему. Я не знал, что скрипт заблокируется, когда встретит ‘post = this.state.post’, я думал, что он пропустит его и повторит попытку во время повторного рендеринга, когда данные будут там. Спасибо, что пытались мне помочь.

Ответ №2:

Ваши данные не загружены. Сначала проверьте:

 return (
  <div>
   <p>{this.state.post amp;amp; this.state.post.body}</p>
  </div>
);