เมื่อใดควรใช้ React“ componentDidUpdate” method?


110

ฉันเขียนหลายสิบReactไฟล์ไม่เคยใช้componentDidUpdateวิธีการ

มีตัวอย่างทั่วไปว่าเมื่อใดที่จำเป็นต้องใช้วิธีนี้?

ฉันต้องการตัวอย่างในโลกแห่งความเป็นจริงไม่ใช่การสาธิตง่ายๆ

ขอบคุณสำหรับคำตอบ!



กรณีง่ายๆเมื่อคุณต้องการตั้งค่าสถานะเริ่มต้นของส่วนประกอบเมื่อโหลด
Rajesh

@ Rajesh ช่วยอธิบายหรือยกตัวอย่างหน่อยได้ไหม? ขอบคุณ!
สไลด์โชว์

1
ฉันคิดว่ากรณีการใช้งานที่พบบ่อยที่สุดคือเมื่อคุณมีไลบรารีอื่น ๆ (jQuery, D3 ... ) ที่ทำงานโดยตรงบน DOM ควบคู่ไปกับ React ในสถานการณ์เช่นนี้ถ้าไลบรารีอื่นต้องการทำการแปลง DOM คุณควรใช้ componentDidUpdate เพื่อให้แน่ใจว่า DOM เงาของ React ถูกล้างไปยัง DOM จริง
Jorge

1
เพื่ออธิบายรายละเอียดเกี่ยวกับความคิดเห็นของ @ Jorge: ฉันคิดว่ากรณีที่พบบ่อยที่สุดคือการอ่านจาก DOM จริงหลังจากที่ React ได้อัปเดตแล้ว เช่นเมื่อคุณต้องการทราบขนาดที่แน่นอนขององค์ประกอบ DOM หรือตำแหน่งขององค์ประกอบ DOM ในวิวพอร์ต เช่นสำหรับภาพเคลื่อนไหวหรือช่วงการเปลี่ยนภาพที่คุณต้องการตอบสนองเพื่อจัดการ ฉันขอแนะนำไม่ให้ใช้ jQuery ในการเปลี่ยน DOM หลังจากที่ตอบสนองแล้ว การมี react + ห้องสมุดอื่นเปลี่ยน DOM ชิ้นเดียวกันเป็นความคิดที่ไม่ดี
wintvelt

คำตอบ:


90

ตัวอย่างง่ายๆคือแอปที่รวบรวมข้อมูลอินพุตจากผู้ใช้จากนั้นใช้ Ajax เพื่ออัปโหลดข้อมูลดังกล่าวไปยังฐานข้อมูล นี่คือตัวอย่างที่เรียบง่าย (ยังไม่ได้รัน - อาจมีข้อผิดพลาดทางไวยากรณ์):

export default class Task extends React.Component {
  
  constructor(props, context) {
    super(props, context);
    this.state = {
      name: "",
      age: "",
      country: ""
    };
  }

  componentDidUpdate() {
    this._commitAutoSave();
  }

  _changeName = (e) => {
    this.setState({name: e.target.value});
  }

  _changeAge = (e) => {
    this.setState({age: e.target.value});
  }

  _changeCountry = (e) => {
    this.setState({country: e.target.value});
  }

  _commitAutoSave = () => {
    Ajax.postJSON('/someAPI/json/autosave', {
      name: this.state.name,
      age: this.state.age,
      country: this.state.country
    });
  }

  render() {
    let {name, age, country} = this.state;
    return (
      <form>
        <input type="text" value={name} onChange={this._changeName} />
        <input type="text" value={age} onChange={this._changeAge} />
        <input type="text" value={country} onChange={this._changeCountry} />
      </form>
    );
  }
}

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

ตัวอย่างข้างต้นค่อนข้างเรียบง่าย แต่อาจพิสูจน์ประเด็นได้ การปรับปรุงอาจเป็นการ จำกัด จำนวนครั้งที่บันทึกอัตโนมัติสามารถดำเนินการได้ (เช่นสูงสุดทุกๆ 10 วินาที) เพราะตอนนี้มันจะทำงานในทุกจังหวะการกด

ฉันทำการสาธิตเกี่ยวกับเรื่องนี้ ซอด้วยเพื่อแสดงให้เห็น


สำหรับข้อมูลเพิ่มเติมโปรดดูเอกสารอย่างเป็นทางการ :

componentDidUpdate()จะถูกเรียกใช้ทันทีหลังจากการอัปเดตเกิดขึ้น วิธีนี้ไม่ถูกเรียกสำหรับการเรนเดอร์เริ่มต้น

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


ผมคิดว่าthis.setState({...}, callback)ที่callbackเท่ากับ_commitAutoSaveสิ่งที่คุณคิดว่า? ดังนั้นฉันคิดว่ากรณีนี้สามารถใช้componentDidUpdateวิธีการได้ แต่ไม่จำเป็นต้องใช่ไหม ซอ
สไลด์โชว์

1
ใช่คุณสามารถใช้การโทรกลับได้ แต่ปัญหาจะยุ่งยากขึ้นเมื่อ / หากมีหลาย setStates ที่ทำงานติดต่อกัน
คริส

ขอบคุณสำหรับคำตอบ. ดังนั้นกรณีหนึ่งที่จะใช้componentDidUpdateคือการแก้ปัญหา setStates หลายตัว! ความคิดอื่น ๆ ?
สไลด์โชว์ 2

@novaline ฉันเห็นพวกเขาใช้มันในคอมโพเนนต์เสียงตอบสนองgithub.com/leoasis/react-sound/blob/master/src/index.js .. ฉันไม่แน่ใจว่าทำไมพวกเขาถึงใช้มัน แต่ฉันคิดว่าฉัน d แชร์ลิงค์เพื่อให้คุณดู
Sarah

3
นี่เป็นตัวอย่างที่ดี แต่ไม่มีคำแนะนำที่สำคัญจากเอกสาร React "นี่เป็นสถานที่ที่ดีในการร้องขอเครือข่ายตราบเท่าที่คุณเปรียบเทียบอุปกรณ์ประกอบฉากปัจจุบันกับอุปกรณ์ประกอบฉากก่อนหน้านี้ (เช่นคำขอเครือข่ายอาจไม่จำเป็นหากไม่มีการเปลี่ยนแปลงอุปกรณ์ประกอบฉาก)" reactjs.org/docs/react-component.html#componentdidupdate ในทำนองเดียวกันควรปิดการโทรด้วยตรรกะแบบมีเงื่อนไขทุกครั้งที่โทรsetStateใน CDU
theUtherSide

5

บางครั้งคุณอาจเพิ่มค่าสถานะจากอุปกรณ์ประกอบฉากในตัวสร้างหรือ ComponentDidMount คุณอาจต้องเรียกใช้ setState เมื่ออุปกรณ์ประกอบฉากเปลี่ยนไป แต่คอมโพเนนต์ได้ติดตั้งไว้แล้วดังนั้น componentDidMount จะไม่ทำงานและจะไม่มีตัวสร้าง ในกรณีนี้คุณสามารถใช้ componentDidUpdate ได้เนื่องจากอุปกรณ์ประกอบฉากมีการเปลี่ยนแปลงคุณสามารถเรียกใช้ setState ใน componentDidUpdate ด้วยอุปกรณ์ประกอบฉากใหม่


2

ฉันใช้componentDidUpdate()ใน highchart

นี่คือตัวอย่างง่ายๆของส่วนประกอบนี้

import React, { PropTypes, Component } from 'react';
window.Highcharts = require('highcharts');

export default class Chartline extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      chart: ''
    };
  }

  public componentDidUpdate() {
    // console.log(this.props.candidate, 'this.props.candidate')
    if (this.props.category) {
      const category = this.props.category ? this.props.category : {};
      console.log('category', category);
      window.Highcharts.chart('jobcontainer_' + category._id, {
        title: {
          text: ''
        },
        plotOptions: {
          series: {
            cursor: 'pointer'
          }
        },
        chart: {
          defaultSeriesType: 'spline'
        },
        xAxis: {
          // categories: candidate.dateArr,
          categories: ['Day1', 'Day2', 'Day3', 'Day4', 'Day5', 'Day6', 'Day7'],
          showEmpty: true
        },
        labels: {
          style: {
            color: 'white',
            fontSize: '25px',
            fontFamily: 'SF UI Text'
          }
        },
        series: [
          {
            name: 'Low',
            color: '#9B260A',
            data: category.lowcount
          },
          {
            name: 'High',
            color: '#0E5AAB',
            data: category.highcount
          },
          {
            name: 'Average',
            color: '#12B499',
            data: category.averagecount
          }
        ]
      });
    }
  }
  public render() {
    const category = this.props.category ? this.props.category : {};
    console.log('render category', category);
    return <div id={'jobcontainer_' + category._id} style={{ maxWidth: '400px', height: '180px' }} />;
  }
}

2
componentDidUpdate(prevProps){ 

    if (this.state.authToken==null&&prevProps.authToken==null) {
      AccountKit.getCurrentAccessToken()
      .then(token => {
        if (token) {
          AccountKit.getCurrentAccount().then(account => {
            this.setState({
              authToken: token,
              loggedAccount: account
            });
          });
        } else {
          console.log("No user account logged");
        }
      })
      .catch(e => console.log("Failed to get current access token", e));

    }
}

1

วิธีการตลอดอายุการใช้งานนี้จะถูกเรียกใช้ทันทีที่การอัปเดตเกิดขึ้น กรณีการใช้งานที่พบบ่อยที่สุดสำหรับเมธอด componentDidUpdate () คือการอัพเดต DOM เพื่อตอบสนองต่อการเปลี่ยนแปลง prop หรือสถานะ

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

componentDidUpdate(prevProps) {
 //Typical usage, don't forget to compare the props
 if (this.props.userName !== prevProps.userName) {
   this.fetchData(this.props.userName);
 }
}

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

สำหรับข้อมูลเพิ่มเติมโปรดดูเอกสารอย่างเป็นทางการ:


จะทำอย่างไรในกรณีthis.fetchData is not a function?
tomrlh

tomrlh เป็นการเรียกใช้ฟังก์ชัน
Kashif

0

เมื่อมีบางอย่างในสถานะเปลี่ยนไปและคุณจำเป็นต้องเรียกใช้ผลข้างเคียง (เช่นขอ api - รับใส่โพสต์ลบ) ดังนั้นคุณต้องโทรcomponentDidUpdate()เพราะcomponentDidMount()เรียกแล้ว

หลังจากเรียกใช้ผลข้างเคียงใน componentDidUpdate () คุณสามารถตั้งค่าสถานะเป็นค่าใหม่ตามข้อมูลการตอบสนองในไฟล์then((response) => this.setState({newValue: "here"})). โปรดตรวจสอบให้แน่ใจว่าคุณจำเป็นต้องตรวจสอบprevPropsหรือprevStateเพื่อหลีกเลี่ยงการวนซ้ำแบบไม่มีที่สิ้นสุดเนื่องจากเมื่อตั้งค่าสถานะเป็นค่าใหม่ componentDidUpdate () จะเรียกอีกครั้ง

มี 2 ​​สถานที่ที่จะเรียกใช้ผลข้างเคียงสำหรับแนวทางปฏิบัติที่ดีที่สุด - componentDidMount () และ componentDidUpdate ()

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