#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>
);