简体   繁体   English

用于 API 调用的 React componentDidMount 与 useEffect 挂钩

[英]React componentDidMount vs useEffect hooks for API call

When I am trying to make an API call using in useEffect hook (before the component did mount), somehow the state is not getting updated, hence I am getting an error Cannot read property of undefined .当我尝试使用 in useEffect 钩子(在组件挂载之前)进行 API 调用时,不知何故状态没有得到更新,因此我收到错误Cannot read property of undefined

But if I am converting the same logic to a Class component and making the API call in the componentDidMount function, the code works well.但是,如果我将相同的逻辑转换为 Class 组件并在 componentDidMount 函数中进行 API 调用,则代码运行良好。

Could anyone tell me why?谁能告诉我为什么?

Using useEffect使用 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 Based Component基于类的组件

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

You are not setting state properly in useEffect hook.您没有在useEffect钩子中正确设置状态。 instead of setCustomers({data:data});而不是setCustomers({data:data}); it should be just setCustomers(data);它应该只是setCustomers(data);

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

Now because customers is an array, just map over customers instead of customers.data.map .现在因为customers是一个数组,只需映射customers而不是customers.data.map

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

So the final code will be所以最终的代码将是

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

You are declaring your customers state as an array:您将客户状态声明为数组:

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

But you are passing an object after fetching the data:但是您在获取数据后传递了一个对象:

 setCustomers({ data: data });

That's why your map iteration in the return section fails, because you are setting the state to an object and not an array.这就是 return 部分中的 map 迭代失败的原因,因为您将状态设置为对象而不是数组。 If data is an array you should only assign it like this:如果 data 是一个数组,你应该只像这样分配它:

setCustomers(data);

The componentDidMount works because you are assigning res.data directly to the customers state and it turns out to be similar to: componentDidMount 工作是因为您将 res.data 直接分配给客户状态,结果类似于:

setCustomers(data);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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