React componentDidMount vs useEffect 挂钩用于 API 调用

React componentDidMount vs useEffect hooks for API call

当我试图在 useEffect 挂钩中使用 API 调用时(在组件挂载之前),不知何故状态没有得到更新,因此我收到错误 Cannot read property of undefined

但是如果我将相同的逻辑转换为 Class 组件并在 componentDidMount 函数中进行 API 调用,代码运行良好。

谁能告诉我为什么?

使用useEffect

import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";

export default function Customers() {
  const [customers, setCustomers] = useState([]);

  useEffect(() => {
    axios
      .get("http://localhost:5000/customers")
      .then((res) => {
        const data = res.data;
        setCustomers(data);
      })
      .catch((err) => console.log(err));
  }, []);

  useEffect(() => {
    console.log(customers);
  }, [customers]);

  return (
    <div className="container-fluid d-flex flex-column align-items-center justify-content-center">
      <div className="top">Customers</div>
      <div className="tables">
        <table class="table table-striped table-hover">
          <thead>
            <tr>
              <th scope="col">Account No</th>
              <th scope="col">Name</th>
              <th scope="col">E-mail</th>
              <th scope="col">Balance</th>
            </tr>
          </thead>
          <tbody>
            {customers.data.map((customer) => ( // error on this line.
              <tr>
                <th scope="row">{customer.account_no}</th>
                <td>{customer.name}</td>
                <td>{customer.email}</td>
                <td>{customer.balance}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

Class 基于组件

import React, { Component } from "react";
import axios from "axios";
import "./Customers.css";

export default class Customers extends Component {
  state = {
    customers: [],
  };

  componentDidMount() {
    axios
      .get("http://localhost:5000/customers")
      .then((res) => {
        res.data.sort();
        console.log(res.data);
        this.setState({ customers: res.data });
      })
      .catch((err) => console.log(err));
  }

  render() {
    return (
      <div className="container-fluid main w-75 my-4 d-flex flex-column align-items-center">
        <div className="top p-4 d-flex justify-content-center">
          Our Customers
        </div>
        <div className="tables w-100">
          <table class="table table-striped table-hover">
            <thead>
              <tr>
                <th scope="col">Account No</th>
                <th scope="col">Name</th>
                <th scope="col">E-mail</th>
                <th scope="col">Balance</th>
              </tr>
            </thead>
            <tbody>
              {this.state.customers.map((customer) => (
                <tr>
                  <th scope="row">{customer.account_no}</th>
                  <td>{customer.name}</td>
                  <td>{customer.email}</td>
                  <td>{customer.balance}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}

您没有在 useEffect 挂钩中正确设置状态。而不是 setCustomers({data:data}); 它应该只是 setCustomers(data);

useEffect(() => {
    axios
      .get("http://localhost:5000/customers")
      .then((res) => {
        const data = res.data;
        setCustomers(data);
      })
      .catch((err) => console.log(err));
  }, []);

现在因为 customers 是一个数组,只需映射到 customers 而不是 customers.data.map

customers.map((customer)=>{})

所以最终代码将是

import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";

export default function Customers() {
  const [customers, setCustomers] = useState([]);

  useEffect(() => {
    axios
      .get("http://localhost:5000/customers")
      .then((res) => {
        const data = res.data;
        setCustomers(data);
      })
      .catch((err) => console.log(err));
  }, []);

  useEffect(() => {
    console.log(customers);
  }, [customers]);

  return (
    <div className="container-fluid d-flex flex-column align-items-center justify-content-center">
      <div className="top">Customers</div>
      <div className="tables">
        <table class="table table-striped table-hover">
          <thead>
            <tr>
              <th scope="col">Account No</th>
              <th scope="col">Name</th>
              <th scope="col">E-mail</th>
              <th scope="col">Balance</th>
            </tr>
          </thead>
          <tbody>
            {customers.map((customer) => ( 
              <tr>
                <th scope="row">{customer.account_no}</th>
                <td>{customer.name}</td>
                <td>{customer.email}</td>
                <td>{customer.balance}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

您将客户状态声明为数组:

const [customers, setCustomers] = useState([]);

但是你在获取数据后传递了一个对象:

 setCustomers({ data: data });

这就是 return 部分中的地图迭代失败的原因,因为您将状态设置为对象而不是数组。如果数据是一个数组,你应该只像这样分配它:

setCustomers(data);

componentDidMount 起作用是因为您将 res.data 直接分配给客户状态,结果类似于:

setCustomers(data);