วิธีที่ถูกต้องในการเรียก API ใน react js คืออะไร?


137

ฉันเพิ่งย้ายจาก Angular ไปที่ ReactJs ฉันใช้ jQuery สำหรับการเรียก API ฉันมี API ที่ส่งคืนรายชื่อผู้ใช้แบบสุ่มที่จะพิมพ์ในรายการ

ฉันไม่แน่ใจว่าจะเขียนการเรียก API ของฉันอย่างไร แนวทางปฏิบัติที่ดีที่สุดสำหรับสิ่งนี้คืออะไร?

ฉันลองทำตามขั้นตอนต่อไปนี้ แต่ไม่ได้รับผลลัพธ์ใด ๆ ฉันเปิดให้ใช้ไลบรารี API ทางเลือกหากจำเป็น

ด้านล่างนี้คือรหัสของฉัน:

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
ฉันขึ้นอยู่กับไลบรารีการจัดการของรัฐที่คุณใช้ หากคุณไม่ได้ใช้งานใด ๆ คุณสามารถย้ายการเรียก API ไปยังไฟล์แยกต่างหากและเรียกใช้ฟังก์ชัน api ในสถานการณ์ของคุณในการcomponentDidMountโทรกลับ
เวน

คุณสามารถใช้fetch()แทน jQuery ได้หากคุณใช้ jQuery เพื่อทำคำขอ Ajax เท่านั้น
Fred

ทำไมต้องใช้ Jquery? Jquery เป็นห้องสมุดขนาดใหญ่และไม่จำเป็น
Robin

เพียงแค่เพิ่มที่นี่ซึ่งตอนนี้useEffectน่าจะเป็นที่สำหรับวางสาย api ในขณะนี้ ดูbtholt.github.io/complete-intro-to-react-v5/effects
shw

คำตอบ:


98

ในกรณีนี้คุณสามารถโทร ajax ภายในcomponentDidMountจากนั้นอัปเดตstate

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
ได้ผลขอบคุณ .. คุณช่วยแนะนำฉันหน่อยได้ไหมว่า "ห้องสมุดไหนดีที่สุดสำหรับการจัดการของรัฐที่ดีกว่า"
Raj Rj

3
@Raj Rj ในสมัยนี้ฉันคิดว่ามันคือ Redux
Alexander T.

8
Redux ได้รับความนิยมมากขึ้นในสมัยนี้รูปแบบมาจากการเขียนโปรแกรมเชิงฟังก์ชัน หากคุณมาจากสไตล์ OOP Mobx ( mobxjs.github.io/mobx ) เป็นไลบรารีการจัดการสถานะที่ยอดเยี่ยมช่วยให้คุณมุ่งเน้นไปที่การเขียนโค้ดธุรกิจและลดรหัสสำเร็จรูปของคุณในที่สุด
Nhan Tran

25

คุณอาจต้องการที่จะตรวจสอบมูกเลือดสถาปัตยกรรม ฉันขอแนะนำให้ตรวจสอบReact-Redux Implementationการดำเนินงาน ใส่สาย API ในการดำเนินการของคุณ มันสะอาดกว่าการใส่ไว้ในส่วนประกอบทั้งหมด

การดำเนินการเป็นวิธีการช่วยเหลือที่คุณสามารถเรียกเพื่อเปลี่ยนสถานะแอปพลิเคชันของคุณหรือทำการเรียก API


Troper ขอบคุณ ดังนั้นฉันจะเก็บการเรียกที่เกี่ยวข้องกับ API ไว้ในไฟล์แยกกันหรือไม่ และฉันจะเรียกสิ่งเหล่านี้ใน "คลาสส่วนประกอบ" ของฉันได้อย่างไร? ฉันควรทำตามโครงสร้างโฟลเดอร์แบบใดแนวปฏิบัติที่ดีที่สุดคืออะไร PS- ฉันเพิ่งจะตอบสนองดังนั้นการถามคำถามพื้นฐานนี้
Raj Rj

ในการใช้งาน redux วิธีการดำเนินการจะถูกฉีดเข้าไปในส่วนประกอบ ตอนนี้วิธีการเหล่านี้จะกลายเป็นอุปกรณ์ประกอบฉากของคุณซึ่งคุณสามารถโทรหาได้ คุณสามารถตรวจสอบreact-redux-starter-kitสำหรับโครงสร้าง
Jei Trooper


11

การสนทนานี้มีมาระยะหนึ่งแล้วและคำตอบของ @Alexander T. ให้คำแนะนำที่ดีในการปฏิบัติตามสำหรับ React รุ่นใหม่เช่นฉัน และฉันจะแบ่งปันความรู้เพิ่มเติมเกี่ยวกับการเรียก API เดียวกันหลาย ๆ ครั้งเพื่อรีเฟรชส่วนประกอบฉันคิดว่าน่าจะเป็นปัญหาทั่วไปที่มือใหม่อาจต้องเผชิญในตอนเริ่มต้น

componentWillReceiveProps(nextProps)จากเอกสารอย่างเป็นทางการ :

หากคุณต้องการอัปเดตสถานะเพื่อตอบสนองต่อการเปลี่ยนแปลง prop (เช่นเพื่อรีเซ็ต) คุณสามารถเปรียบเทียบ this.props และ nextProps และดำเนินการเปลี่ยนสถานะโดยใช้ this.setState () ในวิธีนี้

เราสามารถสรุปได้ว่าที่นี่คือสถานที่ที่เราจัดการอุปกรณ์ประกอบฉากจากองค์ประกอบหลักมีการเรียก API และสถานะการอัปเดต

อ้างอิงจากตัวอย่างของ @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 (...)
  }
}

ปรับปรุง

componentWillReceiveProps() จะเลิกใช้งาน

ต่อไปนี้เป็นเพียงวิธีการบางอย่าง (ทั้งหมดในDoc ) ในวงจรชีวิตซึ่งฉันคิดว่าน่าจะเกี่ยวข้องกับการปรับใช้ API ในกรณีทั่วไป: ป้อนคำอธิบายภาพที่นี่

โดยอ้างอิงแผนภาพด้านบน:

  • ปรับใช้ API ใน componentDidMount()

    สถานการณ์ที่เหมาะสมที่จะมีการเรียก API ที่นี่เป็นที่เนื้อหา (จากการตอบสนองของเอพีไอ) ของส่วนนี้จะเป็นแบบคงที่เพียงไฟไหม้ครั้งเดียวในขณะที่องค์ประกอบที่มีการติดตั้งอุปกรณ์ประกอบฉากใหม่จะถูกส่งผ่านจากองค์ประกอบปกครองหรือมีการดำเนินการเพื่อนำไปสู่componentDidMount() คอมโพเนนต์ตรวจสอบความแตกต่างเพื่อเรนเดอร์ใหม่แต่ไม่ติดตั้งใหม่ อ้างจากdoc :re-rendering

หากคุณต้องการโหลดข้อมูลจากปลายทางระยะไกลนี่เป็นสถานที่ที่ดีในการสร้างอินสแตนซ์คำขอเครือข่าย


  • ปรับใช้ API ใน static getDerivedStateFromProps(nextProps, prevState)

เราควรจะสังเกตเห็นว่ามีสองชนิดของการปรับปรุงองค์ประกอบ , setState() องค์ประกอบในปัจจุบันจะไม่นำไปสู่วิธีการนี้เพื่อเรียก แต่อีกการแสดงผลหรืออุปกรณ์ประกอบฉากใหม่จากส่วนประกอบครอบครัวทำ เราพบว่าวิธีนี้จะยิงขณะติดตั้งด้วย

นี่คือสถานที่ที่เหมาะสมในการปรับใช้ API ถ้าเราต้องการที่จะใช้เป็นส่วนประกอบในปัจจุบันเช่นแม่แบบและพารามิเตอร์ใหม่สำหรับ API จะประกอบฉากมาจากส่วนประกอบครอบครัว
เราได้รับการตอบกลับที่แตกต่างจาก API และส่งคืนไฟล์stateที่นี่เพื่อเปลี่ยนเนื้อหาของส่วนประกอบนี้

ตัวอย่างเช่น
เรามีรายการแบบเลื่อนลงสำหรับรถยนต์ที่แตกต่างกันในองค์ประกอบหลักส่วนประกอบนี้ต้องแสดงรายละเอียดของรถที่เลือก


  • ปรับใช้ API ใน componentDidUpdate(prevProps, prevState)

แตกต่างจาก static getDerivedStateFromProps()วิธีนี้จะถูกเรียกใช้ทันทีหลังจากการแสดงผลทุกครั้งยกเว้นการเรนเดอร์เริ่มต้น เราสามารถเรียก API และแสดงความแตกต่างในองค์ประกอบเดียว

ขยายตัวอย่างก่อนหน้านี้:
องค์ประกอบที่จะแสดงรายละเอียดของรถอาจจะมีรายการของชุดของรถคันนี้ถ้าเราต้องการที่จะตรวจสอบการผลิตหนึ่งในปี 2013 เราอาจคลิกหรือเลือกหรือ ... รายการที่จะนำเป็นครั้งแรกsetState()ที่จะสะท้อนให้เห็นถึงนี้ พฤติกรรม (เช่นการไฮไลต์รายการ) ในองค์ประกอบนี้และในสิ่งต่อไปนี้componentDidUpdate()เราจะส่งคำขอของเราพร้อมพารามิเตอร์ใหม่ (สถานะ) หลังจากได้รับการตอบกลับแล้วเราจะsetState()แสดงเนื้อหาที่แตกต่างกันของรายละเอียดรถยนต์อีกครั้ง เพื่อป้องกันไม่ให้สิ่งต่อไปนี้componentDidUpdate()ทำให้เกิดอินฟินิตี้ลูปเราจำเป็นต้องเปรียบเทียบสถานะโดยใช้prevStateที่จุดเริ่มต้นของวิธีนี้เพื่อตัดสินใจว่าเราส่ง API และแสดงเนื้อหาใหม่หรือไม่

วิธีนี้จริงๆอาจจะนำมาใช้เช่นเดียวstatic getDerivedStateFromProps()กับอุปกรณ์ประกอบฉาก แต่จำเป็นที่จะต้องจัดการกับการเปลี่ยนแปลงของโดยใช้props prevPropsและเราจำเป็นต้องร่วมมือcomponentDidMount()เพื่อจัดการการเรียก API ครั้งแรก

อ้างจากdoc :

... นี่เป็นสถานที่ที่ดีในการร้องขอเครือข่ายตราบเท่าที่คุณเปรียบเทียบอุปกรณ์ประกอบฉากปัจจุบันกับอุปกรณ์ประกอบฉากก่อนหน้า ...


10

ฉันต้องการให้คุณดูที่ redux http://redux.js.org/index.html

พวกเขามีวิธีจัดการการเรียก async ที่กำหนดไว้เป็นอย่างดีเช่นการเรียก API และแทนที่จะใช้ jQuery สำหรับการเรียก API ฉันอยากจะแนะนำให้ใช้แพ็คเกจการดึงข้อมูลหรือขอ npm ปัจจุบันเบราว์เซอร์ที่ทันสมัยรองรับการดึงข้อมูลแต่ยังมี shim สำหรับ ฝั่งเซิร์ฟเวอร์

นอกจากนี้ยังมีแพ็คเกจsuperagent ที่น่าทึ่งอีกตัวซึ่งมีตัวเลือกมากมายเมื่อทำการร้องขอ API และใช้งานง่ายมาก


3

ฟังก์ชันการเรนเดอร์ควรบริสุทธิ์หมายความว่าจะใช้สถานะและอุปกรณ์ประกอบฉากในการแสดงผลเท่านั้นอย่าพยายามแก้ไขสถานะในการเรนเดอร์ซึ่งมักจะทำให้เกิดข้อบกพร่องที่น่าเกลียดและประสิทธิภาพลดลงอย่างมาก นอกจากนี้ยังเป็นจุดที่ดีหากคุณแยกการดึงข้อมูลและแสดงข้อกังวลใน React App ของคุณ ขอแนะนำให้คุณอ่านบทความนี้ซึ่งอธิบายแนวคิดนี้ได้เป็นอย่างดี https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm


3

ส่วนนี้จากReact v16.2เอกสารจะตอบคำถามของคุณอ่านเกี่ยวกับ componentDidMount ():

componentDidMount ()

componentDidMount () ถูกเรียกใช้ทันทีหลังจากเมาท์คอมโพเนนต์ การเริ่มต้นที่ต้องใช้โหนด DOM ควรไปที่นี่ หากคุณต้องการโหลดข้อมูลจากปลายทางระยะไกลนี่เป็นสถานที่ที่ดีในการสร้างอินสแตนซ์คำขอเครือข่าย วิธีนี้เป็นจุดที่ดีในการตั้งค่าการสมัครสมาชิกใด ๆ หากคุณทำเช่นนั้นอย่าลืมยกเลิกการสมัครใน componentWillUnmount ()

อย่างที่คุณเห็นcomponentDidMountถือเป็นสถานที่ที่ดีที่สุดและวนรอบในการโทร apiเข้าถึงโหนดซึ่งหมายความว่าในเวลานี้คุณสามารถโทรได้อย่างปลอดภัยอัปเดตมุมมองหรืออะไรก็ตามที่คุณสามารถทำได้เมื่อเอกสารพร้อมหากคุณเป็น เมื่อใช้ jQuery มันควรจะเตือนคุณในฟังก์ชั่น document.ready () ซึ่งคุณสามารถตรวจสอบให้แน่ใจว่าทุกอย่างพร้อมสำหรับทุกสิ่งที่คุณต้องการทำในโค้ดของคุณ ...


3

1) คุณสามารถใช้ F etch APIเพื่อดึงข้อมูลจากจุดสิ้นสุด:

ตัวอย่างการดึงข้อมูลทั้งหมดGithubสำหรับผู้ใช้

  /* 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) ทางเลือกอื่นคือAxios

การใช้ axios คุณสามารถตัดขั้นตอนกลางของการส่งผลลัพธ์ของคำขอ http ไปยังเมธอด. json () ได้ Axios เพียงแค่ส่งคืนวัตถุข้อมูลที่คุณคาดหวัง

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

ตอนนี้คุณสามารถเลือกที่จะดึงข้อมูลโดยใช้กลยุทธ์ใดก็ได้ใน componentDidMount

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

  componentDidMount() {
    this.fetchData ();
  }

ในขณะเดียวกันคุณสามารถแสดงแถบความคืบหน้าในขณะที่ข้อมูลกำลังโหลด

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

2

คุณยังสามารถดึงข้อมูลด้วยตะขอในส่วนประกอบฟังก์ชันของคุณ

ตัวอย่างเต็มด้วย api call: https://codesandbox.io/s/jvvkoo8pq3

ตัวอย่างที่สอง: 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

ในฐานะที่เป็นสถานที่ที่ดีที่สุดและแนวทางปฏิบัติสำหรับการเรียก API ภายนอกคือ React Lifecycle method componentDidMount ()ซึ่งหลังจากดำเนินการเรียก API แล้วคุณควรอัปเดตสถานะโลคัลเพื่อเรียกใช้เมธอดrender ()ใหม่จากนั้นการเปลี่ยนแปลงในสถานะโลคัลที่อัปเดตจะ นำไปใช้กับมุมมองคอมโพเนนต์

เนื่องจากตัวเลือกอื่นสำหรับการเรียกแหล่งข้อมูลภายนอกเริ่มต้นใน React จะชี้ให้เห็นconstructor ()วิธีการของคลาส คอนสตรัคเตอร์เป็นวิธีแรกที่ดำเนินการกับการเริ่มต้นอินสแตนซ์ออบเจ็กต์คอมโพเนนต์ คุณสามารถดูแนวทางนี้ได้ในตัวอย่างเอกสารสำหรับส่วนประกอบระดับสูงกว่าส่วนประกอบลำดับที่สูงกว่า

ไม่ควรใช้method componentWillMount ()และUNSAFE_componentWillMount ()สำหรับการเรียก API ภายนอกเนื่องจากมีวัตถุประสงค์เพื่อเลิกใช้งาน ที่นี่คุณจะได้เห็นสาเหตุที่พบบ่อยทำไมวิธีนี้จะเลิกใช้

อย่างไรก็ตามคุณต้องไม่ใช้วิธีการ render () หรือวิธีการที่เรียกโดยตรงจาก render ()เป็นจุดสำหรับการเรียก API ภายนอก ถ้าคุณทำเช่นนี้คุณแอพลิเคชันจะถูกปิดกั้น


0

วิธีทำความสะอาดคือการทำให้การเรียก API ตรงกันภายในcomponentDidMountกับฟังก์ชั่นลอง / จับ

เมื่อเราเรียก API เราจะได้รับคำตอบ จากนั้นเราใช้วิธี JSON เพื่อแปลงการตอบสนองเป็นวัตถุ JavaScript จากนั้นเราใช้จากวัตถุตอบสนองนั้นเฉพาะออบเจ็กต์ลูกของเขาชื่อ "ผลลัพธ์" (data.results)

ในตอนแรกเรากำหนดให้ "userList" อยู่ในสถานะเป็นอาร์เรย์ว่าง ทันทีที่เราทำการเรียก API และรับข้อมูลจาก API นั้นเราจะกำหนด "ผลลัพธ์" ให้กับ userList โดยใช้เมธอด setStateวิธี

ภายในฟังก์ชั่นการแสดงผลเราบอกว่า userList จะมาจากสถานะ เนื่องจาก userList เป็นอาร์เรย์ของออบเจ็กต์ที่เราแมปผ่านมันเพื่อแสดงรูปภาพชื่อและหมายเลขโทรศัพท์ของ "ผู้ใช้" แต่ละออบเจ็กต์ ในการดึงข้อมูลนี้เราใช้สัญลักษณ์จุด (เช่น user.phone)

บันทึก : ขึ้นอยู่กับ API ของคุณคำตอบของคุณอาจดูแตกต่างออกไป Console.log "การตอบกลับ" ทั้งหมดเพื่อดูว่าคุณต้องการตัวแปรใดจากนั้นกำหนดตัวแปรใน 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

จะเป็นการดีที่จะใช้ axios สำหรับคำร้องขอ api ซึ่งรองรับการยกเลิก interceptors และอื่น ๆ นอกเหนือจาก axios แล้ว l ใช้ react-redux สำหรับการจัดการสถานะและ redux-saga / redux-thunk สำหรับผลข้างเคียง


แม้ว่าจะไม่ถูกต้องเนื่องจากการใช้ axios และ redux เป็นวิธีที่ถูกต้องในการดึงข้อมูลและจัดการสถานะ แต่ก็ไม่ได้ตอบคำถามจริงๆและใกล้เคียงกับความคิดเห็นมากกว่า
Emile Bergeron
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.