简体   繁体   中英

React is not appending rows to table body

I have a React component that makes a fetch request to the sever which returns a JSON list of sites. What I have found is when I attempt to have React render the rows in the table body I get nothing. No errors, no rendering of elements. Nothing, I have console logged the data from response to just before rendering. and all row elements are there as expected? They just don't seem to be rendering and I'm not sure why?

import React from 'react';
import {
    Table,
    Container,
    Row,
    Col,
    Button } from 'reactstrap';
import CreateSite from "./CreateSite";
import Site from "../objects/Site";

const SitesList = (props) => {

    var Sites = () =>{
        var items = [];
        var sites = new Site();
        sites.getSites().then((data) => {

            data.map(item => {
                console.log(item);
                /* console.log output {id: 1, name: "awdaw", created_at: "2020-04-02T22:00:54.000000Z", updated_at: "2020-04-02T22:00:54.000000Z"}id: 1name: "awdaw"created_at: "2020-04-02T22:00:54.000000Z"updated_at: "2020-04-02T22:00:54.000000Z"__proto__: Object
                index.js:388 {id: 2, name: "awdawdawd", created_at: "2020-04-02T22:02:39.000000Z", updated_at: "2020-04-02T22:02:39.000000Z"}id: 2name: "awdawdawd"created_at: "2020-04-02T22:02:39.000000Z"updated_at: "2020-04-02T22:02:39.000000Z"__proto__: Object
                index.js:388 {id: 3, name: "awdawda", created_at: "2020-04-02T22:03:48.000000Z", updated_at: "2020-04-02T22:03:48.000000Z"}id: 3name: "awdawda"created_at: "2020-04-02T22:03:48.000000Z"updated_at: "2020-04-02T22:03:48.000000Z"__proto__: Object
                index.js:388 {id: 4, name: "awdawdwfawdw123123", created_at: "2020-04-02T22:37:38.000000Z", updated_at: "2020-04-02T22:37:38.000000Z"}id: 4name: "awdawdwfawdw123123"created_at: "2020-04-02T22:37:38.000000Z"updated_at: "2020-04-02T22:37:38.000000Z"__proto__: Object
                index.js:388  */
                return items.push(<tr>
                                <th scope="row">1</th>
                                <td>{item.name}</td>
                                <td>{item.created_at}</td>
                                <td>{item.updated_at}</td>
                            </tr>);
            })
        });

        return items;
    };

    var sites = Sites();
    console.log(sites)
    /* 0: {$$typeof: Symbol(react.element), type: "tr", key: null, ref: null, props: {…}, …}
    1: {$$typeof: Symbol(react.element), type: "tr", key: null, ref: null, props: {…}, …}
    2: {$$typeof: Symbol(react.element), type: "tr", key: null, ref: null, props: {…}, …}
    3: {$$typeof: Symbol(react.element), type: "tr", key: null, ref: null, props: {…}, …}
    4: {$$typeof: Symbol(react.element), type: "tr", key: null, ref: null, props: {…}, …}
    length: 5
    __proto__: Array(0) */

    return (
        <Container>
            <div className="p-5 border bg-white shadow mt-5">
                <Row className="m-0 align-items-center mb-3">
                    <h3 className="m-0">Sites</h3>
                    <CreateSite className="ml-auto" />
                </Row>

                <Table responsive>
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>Name</th>

                            <th>Created Date</th>
                            <th>Updated Date</th>

                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                    {sites}
                    </tbody>
                </Table>
            </div>
        </Container>

    );
}

export default SitesList;

React components only rerender when state or props update.

Issue

Your current implementation does the initial render, essentially with nothing for the sites , and once they are fetched and processed, don't actually signal to react that data as arrived and is ready to display.

Solution

Fetch your data when the component mounts and save it to local state, then map the data to JSX in the return.

import React, { useEffect, useState } from "react";
import { Table, Container, Row, Col, Button } from "reactstrap";
import CreateSite from "./CreateSite";
import Site from "../objects/Site";

const SitesList = props => {
  const [sites, setSites] = useState([]);

  useEffect(() => {
    var sites = new Site();
    sites.getSites().then(data => setSites(data));
  }, []);

  return (
    <Container>
      <div className="p-5 border bg-white shadow mt-5">
        <Row className="m-0 align-items-center mb-3">
          <h3 className="m-0">Sites</h3>
          <CreateSite className="ml-auto" />
        </Row>

        <Table responsive>
          <thead>
            <tr>
              <th>#</th>
              <th>Name</th>

              <th>Created Date</th>
              <th>Updated Date</th>

              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {sites.map(item => {
              return (
                <tr>
                  <th scope="row">1</th>
                  <td>{item.name}</td>
                  <td>{item.created_at}</td>
                  <td>{item.updated_at}</td>
                </tr>
              );
            })}
          </tbody>
        </Table>
      </div>
    </Container>
  );
};

Render functions need to be synchronous, so you cannot do anything that relies on a promise inside of them. Instead, you will need to have state in your component. When the component first renders, that state will be an empty array. Then after the initial render you will kick off the load. When that eventually finishes, you'll set state, causing it to render again.

import React, { useState, useEffect } from 'react;

const SitesList = (props) => {
  const [sites, setSites] = useState([]);
  useEffect(() => {
    sites.getSites().then((data) => {
      setSites(data);
    })
  }, []);

  return (
    <Container>
      {/* some components omitted for brevity */}
      <tbody>
        {sites.map(site => (
          <tr>
            <th scope="row">1</th>
            <td>{item.name}</td>
            <td>{item.created_at}</td>
            <td>{item.updated_at}</td>
          </tr>
        ))}
      </tbody>
    </Container>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM