Порядок действий в React.js с fetch

261
15 октября 2021, 14:10

Написал следующий код по примерам с fetch:

import React, { Component} from 'react';
import { Container, Col, Row } from 'reactstrap';
import './Blog.css';

export class Blog extends Component {
    render() {
        return (
            <Container>
                <PostMaker id={4} />
                <PostMaker id={5} />
                <PostMaker id={9} />
            </Container>
        );
    }
}
export class PostMaker extends Component {
    constructor(props) {
        super(props);
        this.state = { id: 0, data: [] };
    }
    componentDidMount() {        
        const url = 'api/article/makenewpost/?id=' + this.props.id;
        fetch(url, {
            method: "GET",
            headers: {
                "Content-Type":"application/json"
            },
        }).then((response) => { this.setState({id: this.props.id, data:response})})       
    }    

    render() {             
        return (<Container>
            <Row>
                <Col xs={12} className="title">
                    <h2>{this.state.data[0].title}</h2>
                </Col>
            </Row>
            <Row>
                <Col xs={12} className="body">
                    <p>{this.state.data[0].body}</p>
                </Col>
            </Row>
        </Container>);
    }
}

Вылезает исключение:

TypeError: Cannot read property 'title' of undefined

Почему так происходит? render происходит перед fetch? Как мне правильно переделать код?

Если нужен метод из контроллера:

public IActionResult MakeNewPost(int id)
{
    var articles = _context.Post.Where(p => p.Id == id).Select(p => p);
    var title = articles.Select(p => p.Title).First();
    var body = articles.Select(p => p.Body).First();
    List<Post> posts = new List<Post>{
           new Post
            {
                Title = title,
                Body = body,
            }};

    return Json(posts.ToArray());
}
Answer 1
  1. componentDidMount срабатывает всегда после первого render.
  2. А даже, если бы и нет, то в силу того, что fetch асинхронен, то даже, если бы componentDidMount срабатывал перед render, то результат fetch всё равно пришёл бы позже render.
  3. В render в самом начале напишите:

    render() {  
        if(!this.state.data || !this.state.data.length)
           return null;
        // а дальше ваш остальной код
    }
    

    Тогда ничего рендериться не будет, пока не получен ответ на fetch запрос. И, следовательно, ошибки не будет.

READ ALSO
Как отменить стандартное действие при нажатии на кнопку &quot;Назад&quot; сразу после открытия страницы

Как отменить стандартное действие при нажатии на кнопку "Назад" сразу после открытия страницы

Хочу отменить стандартное действие при нажатии на кнопку "Назад", есть функция, которая отслеживает нажатие на кнопку "Назад"

182
Объединить 2 массива в один

Объединить 2 массива в один

как объединить их в thisbufArr, чтобы ключами были буквы из leftArray а значение брались по букве из letterArray Пытался пушом но не получалось

169
Ввод входных данных со стороннего ресурса

Ввод входных данных со стороннего ресурса

На сайте с задачами выбрал язык JavaScriptПодскажите, как данные из поля "Test input" записать в первые 3 переменные

156