user11709406
user11709406

Reputation:

How to write the result of the query in the state of React?

Good evening. Half a day to write down the result of the query in the state React. All code

import React, { Component } from "react";
import ReactDOM from "react-dom";
import axios from "axios";

export default class AllCalcs extends Component {
    constructor (props) {
        super(props);

        this.state = {
            calcs: []
        };

        this.listItems = '';

        this.fetchData();
        this.getCalcs();
    }

    fetchData() {
        axios.post('/api/all-calcs')
            .then(response => this.setState({calcs: response.data}))
            .catch(error => console.log(error));
    }

    getCalcs() {
        this.listItems = this.state.calcs.map((calc, index) =>
            <a key={index} href="#" className="list-group-item list-group-item-action flex-column align-items-start">
                <div className="d-flex w-100 justify-content-between">
                    <h5 className="mb-1">{calc.h1}</h5>
                    <small>3 days ago</small>
                </div>
                <p className="mb-1">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget
                    risus varius blandit.</p>
                <small>Donec id elit non mi porta.</small>
            </a>
        );
    }

    render() {
        return (
            <div>
                <div className="list-group">
                    {this.listItems}
                </div>
            </div>
        );
    }
}

if (document.querySelector('#all-calcs')) {
    ReactDOM.render(<AllCalcs />, document.querySelector('#all-calcs'));
}

I'm sure an experienced developer will understand what the problem is and tell you in a second. The point is that by / api / all-calcs we get an array with posts. They need to be written in this.state.calcs so that it can be used in the getCalcs method. Please help me find out what I am doing wrong.

Upvotes: 2

Views: 57

Answers (1)

John Ruddell
John Ruddell

Reputation: 25842

The request is async, so you are setting up the list items before the data comes in. instead you should do it like this.

export default class AllCalcs extends Component {
  constructor(props) {
    super(props);
    this.state = { calcs: [] };
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    axios
      .post('/api/all-calcs')
      .then(response => this.setState({ calcs: response.data }))
      .catch(error => console.log(error));
  }

  getCalcs(calcs || []) {
    return calcs.map((calc, index) => (
      <a
        key={index}
        href="#"
        className="list-group-item list-group-item-action flex-column align-items-start"
      >
        <div className="d-flex w-100 justify-content-between">
          <h5 className="mb-1">{calc.h1}</h5>
          <small>3 days ago</small>
        </div>
        <p className="mb-1">
          Donec id elit non mi porta gravida at eget metus. Maecenas sed diam
          eget risus varius blandit.
        </p>
        <small>Donec id elit non mi porta.</small>
      </a>
    ));
  }

  render() {
    const { calcs } = this.state
    return (
      <div>
        <div className="list-group">{this.getCalcs(calcs)}</div>
      </div>
    );
  }
}

Essentially what you want to do is kick off the request on componentDidMount. And then build the list of items to render when you render. Dont put it on a variable on the class as it is no longer tied to the lifecycle of the class (you wont see updates / render cycles when you store on a property of the class like that)

Upvotes: 2

Related Questions