cách đúng để thực hiện lệnh gọi API trong phản ứng js là gì?


137

Gần đây tôi đã chuyển từ Angular sang ReactJs. Tôi đang sử dụng jQuery cho các cuộc gọi API. Tôi có một API trả về danh sách người dùng ngẫu nhiên sẽ được in trong danh sách.

Tôi không chắc chắn làm thế nào để viết các cuộc gọi API của tôi. Thực hành tốt nhất cho việc này là gì?

Tôi đã thử sau đây nhưng tôi không nhận được bất kỳ đầu ra. Tôi sẵn sàng triển khai các thư viện API thay thế nếu cần thiết.

Dưới đây là mã của tôi:

import React from 'react';

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

  UserList(){
    return $.getJSON('https://randomuser.me/api/')
    .then(function(data) {
      return data.results;
    });
  }

  render() {
    this.UserList().then(function(res){
      this.state = {person: res};
    });
    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">
          {this.state.person.map((item, i) =>{
            return(
              <h1>{item.name.first}</h1>
              <span>{item.cell}, {item.email}</span>
            )
          })}
        <div>
      </div>
    )
  }
}

2
Tôi phụ thuộc vào thư viện quản lý nhà nước mà bạn đang sử dụng. Nếu bạn không sử dụng bất kỳ, bạn có thể di chuyển các cuộc gọi api của mình sang tệp riêng và gọi các hàm api trong tình huống của bạn trong componentDidMountcuộc gọi lại.
giờ

Bạn có thể sử dụng fetch()thay vì jQuery nếu bạn chỉ sử dụng jQuery để thực hiện các yêu cầu Ajax.
Fred

Tại sao nên sử dụng Jquery? Jquery là một thư viện khổng lồ và không cần thiết
Robin

Chỉ cần thêm vào đây hiện tại useEffectcó lẽ là nơi để thực hiện cuộc gọi api bây giờ. Xem btholt.github.io/complete-intro-to-react-v5/effects
shw

Câu trả lời:


98

Trong trường hợp này, bạn có thể thực hiện cuộc gọi ajax bên trong componentDidMount, sau đó cập nhậtstate

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {person: []};
  }

  componentDidMount() {
    this.UserList();
  }

  UserList() {
    $.getJSON('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    const persons = this.state.person.map((item, i) => (
      <div>
        <h1>{ item.name.first }</h1>
        <span>{ item.cell }, { item.email }</span>
      </div>
    ));

    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">{ persons }</div>
      </div>
    );
  }
}

2
Nó đã hoạt động, cảm ơn .. Bạn có thể vui lòng gợi ý cho tôi "cái nào là thư viện tốt nhất để quản lý nhà nước tốt hơn"
Raj Rj

3
@Raj Rj trong những ngày này tôi nghĩ đó là Redux
Alexander T.

8
Redux phổ biến hơn trong những ngày này, phong cách của nó đến từ lập trình chức năng. Nếu bạn đến từ phong cách OOP, Mobx ( mobxjs.github.io/mobx ) là một thư viện quản lý nhà nước tuyệt vời, nó cho phép bạn tập trung vào viết mã kinh doanh và cuối cùng giảm mã soạn sẵn của bạn
Nhân Trần

25

Bạn có thể muốn kiểm tra Flux Architecture . Tôi cũng khuyên bạn nên kiểm tra React-Redux Thực hiện . Đặt cuộc gọi api của bạn trong hành động của bạn. Nó sạch hơn nhiều so với việc đặt tất cả trong thành phần.

Các hành động là loại phương thức trợ giúp mà bạn có thể gọi để thay đổi trạng thái ứng dụng hoặc thực hiện các cuộc gọi api.


Cảm ơn bạn. Vì vậy, tôi có nên giữ các cuộc gọi liên quan đến API của mình trong các tệp riêng biệt không? Và làm thế nào để tôi gọi chúng trong "lớp thành phần" của tôi? Tôi nên làm theo cấu trúc thư mục nào? Cách thực hành tốt nhất là gì? PS- Tôi mới phản ứng nên hỏi những câu hỏi cơ bản này.
Raj Rj

Trong thực hiện redux, các phương thức hành động được đưa vào các thành phần. Các phương thức này sẽ trở thành đạo cụ cho thành phần của bạn mà bạn có thể gọi. Bạn có thể kiểm tra phản ứng-redux-starter-kit cho cấu trúc.
Jei Trooper

12

Sử dụng fetchphương thức bên trong componentDidMountđể cập nhật trạng thái:

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}

11

Cuộc thảo luận này đã được một thời gian và câu trả lời của @Alexander T. đã cung cấp một hướng dẫn tốt để theo dõi những người mới hơn của React như tôi. Và tôi sẽ chia sẻ một số kiến ​​thức bổ sung về việc gọi cùng một API nhiều lần để làm mới thành phần, tôi nghĩ đó có thể là một vấn đề phổ biến mà người mới có thể gặp phải lúc đầu.

componentWillReceiveProps(nextProps), từ tài liệu chính thức :

Nếu bạn cần cập nhật trạng thái để đáp ứng với thay đổi prop (ví dụ: để đặt lại trạng thái), bạn có thể so sánh this.props và nextProps và thực hiện chuyển đổi trạng thái bằng cách sử dụng this.setState () trong phương thức này.

Chúng tôi có thể kết luận rằng đây là nơi chúng tôi xử lý các đạo cụ từ thành phần chính, có các lệnh gọi API và trạng thái cập nhật.

Dựa trên ví dụ của @Alexander T .:

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

  componentDidMount() {
   //For our first load. 
   this.UserList(this.props.group); //maybe something like "groupOne"
  }

  componentWillReceiveProps(nextProps) {
    // Assuming parameter comes from url.
    // let group = window.location.toString().split("/")[*indexParameterLocated*];
    // this.UserList(group);

    // Assuming parameter comes from props that from parent component.
    let group = nextProps.group; // Maybe something like "groupTwo" 
    this.UserList(group);
  }

  UserList(group) {
    $.getJSON('https://randomuser.me/api/' + group)
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    return (...)
  }
}

Cập nhật

componentWillReceiveProps() sẽ bị phản đối

Đây chỉ là một số phương thức (tất cả chúng trong Doc ) trong vòng đời mà tôi nghĩ sẽ liên quan đến việc triển khai API trong trường hợp chung: nhập mô tả hình ảnh ở đây

Bằng cách tham khảo sơ đồ trên:

  • Triển khai API trong componentDidMount()

    Kịch bản thích hợp để có lệnh gọi API ở đây là nội dung (từ phản hồi của API) của thành phần này sẽ ở trạng thái tĩnh, componentDidMount()chỉ kích hoạt một lần trong khi thành phần được gắn, thậm chí các đạo cụ mới được truyền từ thành phần chính hoặc có hành động để dẫn re-rendering.
    Các thành phần kiểm tra sự khác biệt để kết xuất lại nhưng không gắn kết lại .
    Trích dẫn từ doc :

Nếu bạn cần tải dữ liệu từ một điểm cuối từ xa, đây là một nơi tốt để khởi tạo yêu cầu mạng.


  • Triển khai API trong static getDerivedStateFromProps(nextProps, prevState)

Chúng ta nên lưu ý rằng có hai loại cập nhật thành phần , setState() trong thành phần hiện tại sẽ không dẫn phương thức này kích hoạt, nhưng kết xuất lại hoặc đạo cụ mới từ thành phần cha mẹ thì có. Chúng tôi có thể phát hiện ra rằng phương pháp này cũng kích hoạt trong khi lắp.

Đây là nơi thích hợp để triển khai API nếu chúng tôi muốn sử dụng thành phần hiện tại như mẫu và các tham số mới cho API là các đạo cụ đến từ thành phần chính .
Chúng tôi nhận được phản hồi khác nhau từ API và trả lại một cái mới stateở đây để thay đổi nội dung của thành phần này.

Ví dụ:
Chúng tôi có một danh sách thả xuống cho các Xe khác nhau trong thành phần chính, thành phần này cần hiển thị chi tiết của xe đã chọn.


  • Triển khai API trong componentDidUpdate(prevProps, prevState)

Khác với static getDerivedStateFromProps(), phương thức này được gọi ngay lập tức sau mỗi kết xuất ngoại trừ kết xuất ban đầu. Chúng tôi có thể có lệnh gọi API và hiển thị sự khác biệt trong một thành phần.

Mở rộng ví dụ trước:
Thành phần để hiển thị chi tiết Xe hơi có thể chứa danh sách loạt xe này, nếu chúng tôi muốn kiểm tra phiên bản sản xuất 2013, chúng tôi có thể nhấp hoặc chọn hoặc ... mục danh sách để dẫn đầu tiên setState()để phản ánh điều này hành vi (chẳng hạn như làm nổi bật mục danh sách) trong thành phần này và trong phần sau componentDidUpdate()chúng tôi gửi yêu cầu của chúng tôi với các tham số (trạng thái) mới. Sau khi nhận được phản hồi, chúng tôi setState()một lần nữa để hiển thị nội dung khác nhau của các chi tiết Xe hơi. Để ngăn điều sau componentDidUpdate()gây ra vòng lặp vô cực, chúng ta cần so sánh trạng thái bằng cách sử dụng prevStateở đầu phương thức này để quyết định xem chúng ta có gửi API và hiển thị nội dung mới hay không.

Phương pháp này thực sự có thể được sử dụng giống như static getDerivedStateFromProps()với các đạo cụ, nhưng cần xử lý các thay đổi propsbằng cách sử dụng prevProps. Và chúng ta cần hợp tác componentDidMount()để xử lý lệnh gọi API ban đầu.

Trích dẫn từ doc :

... Đây cũng là một nơi tốt để thực hiện các yêu cầu mạng miễn là bạn so sánh các đạo cụ hiện tại với các đạo cụ trước đó ...


10

Tôi muốn bạn có một cái nhìn về redux http://redux.js.org/index.html

Họ có cách xử lý các cuộc gọi async được xác định rất rõ, ví dụ như các cuộc gọi API và thay vì sử dụng jQuery cho các cuộc gọi API, tôi muốn khuyên bạn nên sử dụng các gói tìm nạp hoặc yêu cầu npm, fetch hiện được hỗ trợ bởi các trình duyệt hiện đại, nhưng cũng có sẵn một shim cho phía máy chủ.

Ngoài ra còn có một siêu gói tuyệt vời khác , có rất nhiều tùy chọn khi thực hiện một yêu cầu API và nó rất dễ sử dụng.


3

Chức năng kết xuất phải thuần túy, điều đó có nghĩa là nó chỉ sử dụng trạng thái và đạo cụ để kết xuất, không bao giờ cố gắng sửa đổi trạng thái trong kết xuất, điều này thường gây ra lỗi xấu và giảm hiệu suất đáng kể. Đó cũng là một điểm tốt nếu bạn tách dữ liệu tìm nạp và đưa ra mối quan tâm trong Ứng dụng React của mình. Tôi khuyên bạn nên đọc bài viết này giải thích ý tưởng này rất tốt. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm


3

Phần này từ tài liệu React v16 sẽ trả lời câu hỏi của bạn, hãy đọc về thành phầnDidMount ():

thành phầnDidMount ()

thành phầnDidMount () được gọi ngay lập tức sau khi một thành phần được gắn kết. Khởi tạo yêu cầu các nút DOM nên vào đây. Nếu bạn cần tải dữ liệu từ một điểm cuối từ xa, đây là một nơi tốt để khởi tạo yêu cầu mạng. Phương pháp này là một nơi tốt để thiết lập bất kỳ đăng ký. Nếu bạn làm điều đó, đừng quên hủy đăng ký thành phầnWillUnmount ().

Như bạn thấy, thành phầnDidMount được coi là nơi và chu kỳ tốt nhất để thực hiện cuộc gọi api , cũng truy cập nút, có nghĩa là vào thời điểm này, an toàn để thực hiện cuộc gọi, cập nhật chế độ xem hoặc bất cứ điều gì bạn có thể làm khi tài liệu sẵn sàng, nếu bạn đang bằng cách sử dụng jQuery, bằng cách nào đó nó sẽ nhắc nhở bạn hàm document. yet (), nơi bạn có thể đảm bảo mọi thứ đã sẵn sàng cho bất cứ điều gì bạn muốn làm trong mã của mình ...


3

1) Bạn có thể sử dụng API F etch để tìm nạp dữ liệu từ Điểm cuối:

Ví dụ tìm nạp tất cả Githubnghỉ ngơi cho người dùng

  /* Fetch GitHub Repos */
  fetchData = () => {

       //show progress bar
      this.setState({ isLoading: true });

      //fetch repos
      fetch(`https://api.github.com/users/hiteshsahu/repos`)
      .then(response => response.json())
      .then(data => {
        if (Array.isArray(data)) {
          console.log(JSON.stringify(data));
          this.setState({ repos: data ,
                         isLoading: false});
        } else {
          this.setState({ repos: [],
                          isLoading: false  
                        });
        }
      });
  };

2) Thay thế khác là Axios

Sử dụng các axios bạn có thể cắt bỏ bước giữa để chuyển kết quả của yêu cầu http sang phương thức .json (). Axios chỉ trả về đối tượng dữ liệu mà bạn mong đợi.

  import axios from "axios";

 /* Fetch GitHub Repos */
  fetchDataWithAxios = () => {

     //show progress bar
      this.setState({ isLoading: true });

      // fetch repos with axios
      axios
          .get(`https://api.github.com/users/hiteshsahu/repos`)
          .then(result => {
            console.log(result);
            this.setState({
              repos: result.data,
              isLoading: false
            });
          })
          .catch(error =>
            this.setState({
              error,
              isLoading: false
            })
          );
}

Bây giờ bạn có thể chọn tìm nạp dữ liệu bằng bất kỳ chiến lược nào trong componentDidMount

class App extends React.Component {
  state = {
    repos: [],
   isLoading: false
  };

  componentDidMount() {
    this.fetchData ();
  }

Trong khi đó, bạn có thể hiển thị thanh tiến trình trong khi dữ liệu đang tải

   {this.state.isLoading && <LinearProgress />}

2

Bạn cũng có thể tìm nạp dữ liệu bằng hook trong các thành phần chức năng của mình

ví dụ đầy đủ với cuộc gọi api: https://codesandbox.io/s/jvvkoo8pq3

ví dụ thứ hai: https://jsfiddle.net/bradcypert/jhrt40yv/6/

const Repos = ({user}) => {
  const [repos, setRepos] = React.useState([]);

  React.useEffect(() => {
    const fetchData = async () => {
        const response = await axios.get(`https://api.github.com/users/${user}/repos`);
        setRepos(response.data);
    }

    fetchData();
  }, []);

  return (
  <div>
    {repos.map(repo =>
      <div key={repo.id}>{repo.name}</div>
    )}
  </div>
  );
}

ReactDOM.render(<Repos user="bradcypert" />, document.querySelector("#app"))

1

Vì vị trí và cách thực hành tốt nhất cho các lệnh gọi API bên ngoài là phương thức React Lifecycl thành phầnDidMount () , trong đó sau khi thực hiện lệnh gọi API, bạn nên cập nhật trạng thái cục bộ để được kích hoạt kết xuất mới () lệnh gọi phương thức , sau đó các thay đổi trong trạng thái cục bộ được cập nhật sẽ được áp dụng trên khung nhìn thành phần.

Như tùy chọn khác cho cuộc gọi nguồn dữ liệu ngoài ban đầu trong React được chỉ ra phương thức constructor () của lớp. Hàm tạo là phương thức đầu tiên được thực thi khi khởi tạo thể hiện đối tượng thành phần. Bạn có thể thấy cách tiếp cận này trong các ví dụ tài liệu cho các Thành phần bậc cao .

Không nên sử dụng thành phần phương thứcWillMount ()UNSAFE_componentWillMount () cho các lệnh gọi API bên ngoài, vì chúng được dự định không dùng nữa. Ở đây bạn có thể thấy những lý do phổ biến, tại sao phương pháp này sẽ không được chấp nhận.

Dù sao, bạn không bao giờ phải sử dụng phương thức render () hoặc phương thức được gọi trực tiếp từ render () làm điểm cho lệnh gọi API bên ngoài. Nếu bạn làm điều này, ứng dụng của bạn sẽ bị chặn .


0

Một cách rõ ràng là thực hiện cuộc gọi API không đồng bộ bên trong thành phầnDidMount với chức năng thử / bắt .

Khi chúng tôi gọi một API, chúng tôi nhận được phản hồi. Sau đó, chúng tôi áp dụng phương thức JSON trên nó, để chuyển đổi phản hồi thành đối tượng JavaScript. Sau đó, chúng tôi lấy từ đối tượng phản hồi đó chỉ đối tượng con của mình có tên là "results" (data.results).

Ban đầu, chúng tôi đã định nghĩa "userList" ở trạng thái là một mảng trống. Ngay khi chúng tôi thực hiện cuộc gọi API và nhận dữ liệu từ API đó, chúng tôi sẽ gán "kết quả" cho userList bằng phương thức setState .

Bên trong chức năng kết xuất, chúng tôi nói rằng userList sẽ đến từ trạng thái. Vì userList là một mảng các đối tượng chúng ta ánh xạ qua nó, để hiển thị một hình ảnh, tên và số điện thoại của từng đối tượng "người dùng". Để lấy thông tin này, chúng tôi sử dụng ký hiệu chấm (ví dụ: user.phone).

GHI CHÚ : tùy thuộc vào API của bạn, phản hồi của bạn có thể khác. Console.log toàn bộ "phản hồi" để xem bạn cần biến nào từ nó, sau đó gán chúng trong setState.

UserList.js

import React, { Component } from "react";

export default class UserList extends Component {
   state = {
      userList: [], // list is empty in the beginning
      error: false
   };

   componentDidMount() {
       this.getUserList(); // function call
   }

   getUserList = async () => {
       try { //try to get data
           const response = await fetch("https://randomuser.me/api/");
           if (response.ok) { // ckeck if status code is 200
               const data = await response.json();
               this.setState({ userList: data.results});
           } else { this.setState({ error: true }) }
       } catch (e) { //code will jump here if there is a network problem
   this.setState({ error: true });
  }
};

  render() {
  const { userList, error } = this.state
      return (
          <div>
            {userList.length > 0 && userList.map(user => (
              <div key={user}>
                  <img src={user.picture.medium} alt="user"/>
                  <div>
                      <div>{user.name.first}{user.name.last}</div>
                      <div>{user.phone}</div>
                      <div>{user.email}</div>
                  </div>
              </div>
            ))}
            {error && <div>Sorry, can not display the data</div>}
          </div>
      )
}}

0

Sẽ thật tuyệt khi sử dụng axios cho yêu cầu api hỗ trợ hủy, chặn, v.v. Cùng với axios, tôi sử dụng Reac-redux để quản lý nhà nước và redux-saga / redux-thunk cho các tác dụng phụ.


Mặc dù điều này không chính xác, vì sử dụng axios và redux là một cách hợp lệ để tìm nạp dữ liệu và quản lý trạng thái, nó không thực sự trả lời câu hỏi và nó gần với một bình luận hơn.
Emile Bergeron
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.