ส่วนประกอบทำปฏิกิริยาเริ่มต้นสถานะจากอุปกรณ์ประกอบฉาก


204

ใน React มีความแตกต่างที่แท้จริงระหว่างการใช้งานทั้งสองนี้หรือไม่ เพื่อนบางคนบอกฉันว่า FirstComponent เป็นรูปแบบ แต่ฉันไม่เห็นว่าทำไม SecondComponent ดูง่ายขึ้นเพราะการเรนเดอร์ถูกเรียกเพียงครั้งเดียว

ครั้งแรก:

import React, { PropTypes } from 'react'

class FirstComponent extends React.Component {

  state = {
    description: ''
  }

  componentDidMount() {
    const { description} = this.props;
    this.setState({ description });
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} /> 
    );
  }
}

export default FirstComponent;

ประการที่สอง:

import React, { PropTypes } from 'react'

class SecondComponent extends React.Component {

  state = {
    description: ''
  }

  constructor (props) => {
    const { description } = props;
    this.state = {description};
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} />   
    );
  }
}

export default SecondComponent;

อัปเดต: ฉันเปลี่ยน setState () เป็น this.state = {} (ขอขอบคุณ joews) อย่างไรก็ตามฉันยังไม่เห็นความแตกต่าง ดีกว่าอีกไหม?


10
ทำไมคุณถึงจัดเก็บอุปกรณ์ประกอบฉากของคุณในรัฐ? คุณควรใช้อุปกรณ์ประกอบฉากของคุณโดยตรงแทนการแคชค่า ได้อ่านของทำไมการตั้งค่าอุปกรณ์ประกอบฉากเป็นของรัฐใน React.js ถูกดูหมิ่นและอุปกรณ์ประกอบฉากใน getInitialState คือการต่อต้านแบบ
Aurora0001

12
ตัวอย่าง - องค์ประกอบที่สลับได้ (เช่นป๊อปโอเวอร์หรือลิ้นชัก) ผู้ปกครองรู้ว่าองค์ประกอบควรเริ่มเปิดหรือปิด; องค์ประกอบเองอาจรู้ว่าเปิดอยู่หรือไม่ ณ จุดหนึ่ง ในกรณีนั้นฉันคิดว่าthis.state = { isVisible: props.isVisible }สมเหตุสมผล ขึ้นอยู่กับวิธีที่แอพกระจายสถานะ UI
joews

2
คุณควรอ่านmedium.com/@justintulk/
FDisk

5
ในปี 2560 Facebook สาธิตการใช้อุปกรณ์ประกอบฉากเพื่อกำหนดสถานะเริ่มต้นในเอกสารประกอบของพวกเขา: reactjs.org/docs/react-component.html#constructor
Rohmer

1
@ Aurora0001 ในสถานการณ์ที่คุณต้องจัดการกับฟอร์มให้พูดแบบฟอร์มแก้ไขที่จะทำให้คำขอเครือข่ายเป็นของตัวเอง แต่คุณต้องเริ่มต้นอินพุตที่มีค่าที่จะมาเป็นส่วนประกอบขององค์ประกอบนั้น เพื่อที่จะรักษารูปแบบไดนามิกค่าเหล่านั้นจะต้องถูกเก็บไว้ในสถานะ
Eric McWinNEr

คำตอบ:


196

ควรสังเกตว่ามันเป็นรูปแบบการต่อต้านในการคัดลอกคุณสมบัติที่ไม่เคยเปลี่ยนเป็นสถานะ (เพียงเข้าถึง. props โดยตรงในกรณีนั้น) หากคุณมีตัวแปรสถานะที่จะเปลี่ยนในที่สุด แต่เริ่มต้นด้วยค่าจาก. โปรแกรมคุณไม่จำเป็นต้องมีการเรียกตัวสร้าง - ตัวแปรท้องถิ่นเหล่านี้จะเริ่มต้นหลังจากการเรียกไปยังตัวสร้างของผู้ปกครอง:

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

นี่เทียบเท่ากับคำตอบจาก @joews ด้านล่าง ดูเหมือนว่าจะทำงานเฉพาะกับ transpilers รุ่นล่าสุดของ ES6 ฉันมีปัญหากับการตั้งค่า webpack บางอย่าง หากวิธีนี้ไม่ได้ผลสำหรับคุณคุณสามารถลองเพิ่มปลั๊กอินของ babel babel-plugin-transform-class-propertiesหรือคุณสามารถใช้เวอร์ชันที่ไม่ใช่แบบย่อโดย @joews ด้านล่าง


1
คุณช่วยอธิบายเพิ่มเติมได้อย่างไรว่าคำตอบของคุณแตกต่างจาก @joews ตอบอย่างไร
Jalal

3
เพิ่ม "คุณสามารถข้ามการเรียก constructor ได้หากสิ่งที่คุณทำคือการตั้งค่าตัวแปร"
Zane Hooper

3
หากไม่ได้ผลคุณอาจต้องติดตั้ง babel plugin นี้ "babel-plugin-transform-class-properties"
Faheem

2
ไม่ใช่รูปแบบการต่อต้านที่จะเริ่มต้นสถานะจากอุปกรณ์ประกอบฉากหากเข้าใจว่ารัฐไม่พึ่งพาอุปกรณ์ประกอบฉากหลังจากการเริ่มต้น หากคุณพยายามที่จะทำให้ทั้งสองซิงค์กันอยู่นั่นเป็นรูปแบบการต่อต้าน
Yatrix

1
@ ak85 เป็นไวยากรณ์เดียวกัน แต่คุณจะใช้ this.state แทน ไวยากรณ์นี้เป็นเพียงรูปแบบย่อสำหรับการตั้งค่าสถานะในระหว่างกระบวนการสร้างคลาส (และสามารถใช้สำหรับตัวแปรอื่นที่ไม่ใช่ของรัฐได้เช่นกัน)
Zane Hooper

137

คุณไม่จำเป็นต้องโทรหาsetStateตัวแทนconstructor- มันเป็นเรื่องง่ายที่จะตั้งค่าthis.stateโดยตรง:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

ดูปฏิกิริยาเอกสาร - เพิ่มรัฐท้องถิ่นชั้น

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


4
คำตอบที่ดี. มันอาจจะน่าสังเกตว่านี่เป็นเพียงการตั้งค่าสถานะเริ่มต้น; คุณยังจำเป็นต้องใช้setStateหากคุณทำการเปลี่ยนแปลงที่จุดอื่นมิฉะนั้นการเปลี่ยนแปลงอาจไม่แสดงผล
Aurora0001

ขอขอบคุณอีกครั้ง jowes สองเอกสารfacebook.github.io/react/docs/ …
Levy Moreira

(ขออภัยฉันกด Enter .. ) เราควรใช้ getInitialState เพื่อกำหนดอุปกรณ์ประกอบฉากให้ระบุในงานที่ซับซ้อนมากขึ้นถ้าเป็นเรื่องง่ายเราก็สามารถใช้ this.props ในการเรนเดอร์ได้ไหม?
Levy Moreira

1
บนหมายเหตุ: ใช้super(props)ในตัวสร้าง การอภิปรายเกี่ยวกับ SO
cutemachine

2
ข้อเสนอแนะของ Joews นั้นใช้งานได้ในกรณีส่วนใหญ่ แต่ระวังการส่งอุปกรณ์ประกอบฉากไปยังรัฐนี้โดยตรง คัดลอก Props เพื่อ this.state เป็นจริง againt แหล่งเดียวของความจริง ( medium.com/react-ecosystem/... ) นอกจากนี้ Dan Abramov เคยแนะนำว่าอย่าเก็บค่าอุปกรณ์ประกอบฉากในสถานะ ( twitter.com/dan_abramov/status/749710501916139520/photo/1 )
ฮิโระกิ

33

การปรับปรุงสำหรับตอบสนอง 16.3อัลฟาแนะนำstatic getDerivedStateFromProps(nextProps, prevState)( เอกสาร ) componentWillReceivePropsแทนสำหรับ

getDerivedStateFromProps ถูกเรียกใช้หลังจากที่คอมโพเนนต์ถูกสร้างอินสแตนซ์และเมื่อได้รับอุปกรณ์ประกอบฉากใหม่ มันควรจะคืนค่าออบเจกต์เพื่ออัพเดทสถานะหรือโมฆะเพื่อระบุว่าอุปกรณ์ประกอบฉากใหม่ไม่ต้องการการอัพเดทสถานะใด ๆ

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

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

มันเป็นแบบคงที่ดังนั้นจึงไม่สามารถเข้าถึงได้โดยตรงthis(แต่มันมีการเข้าถึงprevStateซึ่งสามารถจัดเก็บสิ่งต่าง ๆ ที่แนบมาตามปกติthisเช่นrefs)

แก้ไขเพื่อสะท้อนการแก้ไขของ @ nerfologist ในความคิดเห็น


3
เพียงชี้แจงก็ชื่อgetDerivedStateFromProps(ทำเครื่องหมายตัวอักษรในอุปกรณ์ประกอบฉาก) และพารามิเตอร์ที่มีnextProps, prevState(ไม่nextState): reactjs.org/docs/...
nerfologist

1
ว้าว! เราสามารถใช้สิ่งนี้เพื่ออัปเดตสถานะเมื่อได้รับอุปกรณ์ที่อัปเดตแล้ว !
Aromal Sasidharan

2
เรายังต้องสร้างสถานะเริ่มต้นในตัวสร้างโดยพิจารณาว่าgetDerivedStateFromPropsมีการเรียกเสมอก่อนการเรนเดอร์เริ่มต้นหรือไม่?
bvdb

19

คุณสามารถใช้แบบฟอร์มสั้น ๆ ด้านล่างหากคุณต้องการเพิ่มอุปกรณ์ประกอบฉากทั้งหมดเพื่อระบุและรักษาชื่อเดิมไว้

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}

1
มันเป็นรูปแบบการต่อต้านการคัดลอกคุณสมบัติที่ไม่เคยเปลี่ยนเป็นรัฐ เป็นการดีกว่าที่จะอธิบายอย่างชัดเจนว่าฟิลด์ใดที่คอมโพเนนต์ของคุณใช้
Michael Freidgeim

5

ตั้งค่าข้อมูลสถานะภายในตัวสร้างเช่นนี้

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
  }

มันจะไม่ทำงานหากคุณตั้งค่าใน componentDidMount () ด้านวิธีการผ่านอุปกรณ์ประกอบฉาก


3

หากคุณเริ่มต้นสถานะโดยตรงจากอุปกรณ์ประกอบฉากมันจะแสดงคำเตือนในการตอบสนอง 16.5 (5 กันยายน 2018)


ความคิดใด ๆ ว่าทำไมมันจะเตือน?
Nitin Jadhav

2
state = propsมันดูเหมือนว่ามันเท่านั้นถ้าคุณใช้ ข้อมูลเพิ่มเติมที่นี่: github.com/facebook/react/pull/11658#issuecomment-419677176
ตอนนี้

2

คุณสามารถใช้keyค่าเพื่อรีเซ็ตสถานะเมื่อต้องการส่งผ่านอุปกรณ์ประกอบฉากเพื่อระบุว่าไม่ใช่วิธีปฏิบัติที่ดีเพราะคุณมีส่วนประกอบที่ไม่สามารถควบคุมและควบคุมได้ในที่เดียว ข้อมูลที่ควรจะอยู่ในสถานที่แห่งหนึ่งสถานการณ์รูปอ่าน https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a -สำคัญ


1

คุณสามารถใช้ componentWillReceiveProps

constructor(props) {
    super(props);
    this.state = {
      productdatail: ''
    };
  }

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }

1
componentWillReceiveProps ไม่สามารถใช้กับรุ่นในอนาคตได้
Vivek Ghanchi

1

คุณต้องระวังเมื่อคุณเริ่มต้นstateจากpropsในตัวสร้าง แม้ว่าจะpropsเปลี่ยนเป็นใหม่ แต่รัฐก็จะไม่เปลี่ยนเพราะการเมาท์จะไม่เกิดขึ้นอีก ดังนั้นgetDerivedStateFromPropsอยู่ที่

class FirstComponent extends React.Component {
    state = {
        description: ""
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }

        return null;
    }

    render() {
        const {state: {description}} = this;    

        return (
            <input type="text" value={description} /> 
        );
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.