【问题标题】:React componentDidMount vs useEffect hooks for API call用于 API 调用的 React componentDidMount 与 useEffect 挂钩
【发布时间】:2021-06-23 12:47:20
【问题描述】:

当我尝试使用 in 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>
  );
}

基于类的组件

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

【问题讨论】:

    标签: reactjs use-effect react-component react-lifecycle-hooks


    【解决方案1】:

    您没有在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>
      );
    }
    

    【讨论】:

    • 感谢您的澄清,但它似乎不起作用。得到同样的错误。
    • 更新答案
    【解决方案2】:

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

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

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

     setCustomers({ data: data });
    

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

    setCustomers(data);
    

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

    setCustomers(data);
    

    【讨论】:

    • 我试过了,还是报同样的错误:(
    猜你喜欢
    • 2020-10-15
    • 2021-01-10
    • 1970-01-01
    • 2020-09-07
    • 2021-11-14
    • 2021-12-01
    • 2020-09-18
    • 1970-01-01
    • 2019-10-08
    相关资源
    最近更新 更多