Bereaksi komponen menginisialisasi keadaan dari alat peraga

205

Dalam Bereaksi, apakah ada perbedaan nyata antara kedua implementasi ini? Beberapa teman mengatakan kepada saya bahwa FirstComponent adalah polanya, tetapi saya tidak mengerti mengapa. Komponen Kedua tampaknya lebih sederhana karena render disebut hanya sekali.

Pertama:

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;

Kedua:

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;

Pembaruan: Saya mengubah setState () ke this.state = {} (thanks joews), Namun, saya masih tidak melihat perbedaannya. Apakah yang satu lebih baik dari yang lain?

Levy Moreira
sumber
10
Mengapa Anda menyimpan alat peraga di negara bagian? Anda harus menggunakan alat peraga Anda secara langsung sebagai gantinya, daripada menyimpan nilai. Telah membaca tentang Mengapa Mengatur Alat Peraga sebagai Status di React.js adalah Penghujatan dan Alat Peraga di getInitialState Adalah Anti-Pola .
Aurora0001
12
Contoh - komponen yang dapat diganti (mis. Popover atau laci). Induk tahu apakah komponen harus mulai terbuka atau tertutup; komponen itu sendiri mungkin tahu apakah itu terbuka atau tidak pada suatu titik waktu. Dalam hal ini saya pikir this.state = { isVisible: props.isVisible }masuk akal. Tergantung pada bagaimana aplikasi mendistribusikan keadaan UI.
joews
2
Anda harus membaca ini medium.com/@justintulk/...
fdisk
5
Pada 2017, Facebook menunjukkan menggunakan alat peraga untuk menetapkan keadaan awal dalam dokumentasi mereka: reactjs.org/docs/react-component.html#constructor
Rohmer
1
@ Aurora0001 Bagaimana dalam situasi di mana Anda perlu menangani formulir, katakanlah formulir edit yang akan membuat permintaan jaringan sendiri tetapi Anda perlu menginisialisasi input dengan nilai-nilai yang akan datang sebagai alat peraga untuk komponen itu. Untuk menjaga agar form tetap dinamis, nilai-nilai itu harus tetap dalam keadaan.
Eric McWinNEr

Jawaban:

196

Perlu dicatat bahwa ini adalah anti-pola untuk menyalin properti yang tidak pernah berubah ke keadaan (cukup akses .props langsung dalam kasus itu). Jika Anda memiliki variabel keadaan yang pada akhirnya akan berubah tetapi dimulai dengan nilai dari .props, Anda bahkan tidak memerlukan panggilan konstruktor - variabel lokal ini diinisialisasi setelah panggilan ke konstruktor induk:

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

Ini adalah singkatan yang setara dengan jawaban dari @ yoews di bawah ini. Tampaknya hanya bekerja pada versi yang lebih baru dari es6 transpiler, saya memiliki masalah dengan itu pada beberapa pengaturan webpack. Jika ini tidak berhasil untuk Anda, Anda dapat mencoba menambahkan plugin babel babel-plugin-transform-class-properties, atau Anda dapat menggunakan versi non-steno oleh @ joews di bawah ini.

Zane Hooper
sumber
1
dapatkah Anda menjelaskan lebih lanjut bagaimana jawaban Anda berbeda dari jawaban @ yoy?
Jalal
3
Ditambahkan "Anda dapat melewatkan panggilan konstruktor jika semua yang Anda lakukan adalah mengatur variabel."
Zane Hooper
3
Jika tidak berhasil, Anda mungkin perlu menginstal plugin babel ini "babel-plugin-transform-class-properties".
Faheem
2
Ini bukan anti-pola untuk menginisialisasi keadaan dari alat peraga jika dipahami bahwa negara tidak bergantung pada alat peraga setelah inisialisasi. Jika Anda mencoba menjaga keduanya tetap sinkron, itu anti-pola.
Yatrix
1
@ ak85 itu adalah sintaks yang sama tetapi Anda akan menggunakan this.state sebagai gantinya. Sintaks ini hanya sintaks singkatan untuk menetapkan negara selama proses konstruksi kelas (dan juga dapat digunakan untuk variabel selain keadaan)
Zane Hooper
137

Anda tidak perlu memanggil setStateKomponen constructor- itu idiomatis untuk mengatur this.statelangsung:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

Lihat Bereaksi dokumen - Menambahkan Status Lokal ke Kelas .

Tidak ada keuntungan dengan metode pertama yang Anda gambarkan. Ini akan menghasilkan pembaruan kedua segera sebelum memasang komponen untuk pertama kalinya.

joews
sumber
4
Jawaban yang bagus. Mungkin perlu dicatat bahwa ini hanya untuk pengaturan keadaan awal; Anda masih perlu menggunakan setStatejika Anda memutasinya di titik lain, jika tidak perubahan itu tidak akan merender.
Aurora0001
Terima kasih lagi jowes, kedua dokumentasi facebook.github.io/react/docs/…
Levy Moreira
(maaf saya tekan enter ..) kita harus menggunakan getInitialState untuk mengatur props untuk menyatakan, dalam tugas yang lebih kompleks, jika sederhana kita bisa menggunakan this.props ke render, benar?
Levy Moreira
1
Pada catatan pinggir: gunakan super(props)di konstruktor. Diskusi tentang SO
cutemachine
2
saran joews 'bekerja dalam banyak kasus, tetapi hati-hati tentang mengirim alat peraga ke status ini secara langsung. Menyalin props ke this.state sebenarnya melawan satu sumber kebenaran ( medium.com/react-ecosystem/… ). Juga, Dan Abramov pernah menyarankan untuk tidak menyimpan nilai props di negara bagian. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki
33

Pembaruan untuk Bereaksi 16.3 alfa diperkenalkan static getDerivedStateFromProps(nextProps, prevState)( dokumen ) sebagai pengganti componentWillReceiveProps.

getDerivedStateFromProps dipanggil setelah komponen di-instantiate juga ketika menerima props baru. Ini harus mengembalikan objek untuk memperbarui keadaan, atau nol untuk menunjukkan bahwa alat peraga baru tidak memerlukan pembaruan keadaan apa pun.

Perhatikan bahwa jika komponen induk menyebabkan komponen Anda untuk merender ulang, metode ini akan dipanggil meskipun props tidak berubah. Anda mungkin ingin membandingkan nilai-nilai baru dan sebelumnya jika Anda hanya ingin menangani perubahan.

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

Itu statis, oleh karena itu ia tidak memiliki akses langsung ke this(tetapi ia memiliki akses ke prevState, yang dapat menyimpan hal-hal yang biasanya terpasang thismisalnyarefs )

diedit untuk mencerminkan koreksi @ nerfologist dalam komentar

Ashley Coolman
sumber
3
Hanya untuk memperjelas, itu dinamai getDerivedStateFromProps(tandai huruf kapital di Props) dan params adalah nextProps, prevState(tidak nextState): reactjs.org/docs/…
nerfologist
1
Wow! kita dapat menggunakan ini untuk memperbarui status ketika alat peraga yang diperbarui diterima!
Aromal Sasidharan
2
Apakah kita masih harus membuat keadaan awal dalam konstruktor, mengingat getDerivedStateFromPropsselalu dipanggil sebelum rendering awal?
bvdb
19

Anda bisa menggunakan formulir pendek seperti di bawah ini jika Anda ingin menambahkan semua alat peraga untuk menyatakan dan mempertahankan nama yang sama.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
dacharjaya
sumber
1
ini merupakan anti-pola untuk menyalin properti yang tidak pernah berubah ke status. Lebih baik untuk secara eksplisit menjelaskan bidang mana yang digunakan komponen Anda.
Michael Freidgeim
5

atur data keadaan di dalam konstruktor seperti ini

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

itu tidak akan berfungsi jika Anda mengatur di sisi componentDidMount () metode melalui alat peraga.

Krishna Kumar Jangid
sumber
3

Jika Anda secara langsung init negara dari alat peraga, itu akan menampilkan peringatan dalam Bereaksi 16.5 (5 September 2018)

Sujith S
sumber
tahu mengapa itu akan memperingatkan?
Nitin Jadhav
2
Sepertinya itu hanya jika Anda gunakan state = props. Info lebih lanjut di sini: github.com/facebook/react/pull/11658#issuecomment-419677176
sekarang
1

Anda dapat menggunakan componentWillReceiveProps.

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }
Ankit Kumar Rajpoot
sumber
1
componentWillReceiveProps sudah usang tidak dapat digunakan untuk versi masa depan
Vivek Ghanchi
1

ANDA HARUS HATI-HATI saat Anda menginisialisasi statedari propsdalam konstruktor. Bahkan jika propsdiubah ke yang baru, keadaan tidak akan berubah karena mount tidak pernah terjadi lagi. Jadi getDerivedStateFromPropsada untuk itu.

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} /> 
        );
    }
}
Yonggoo Noh
sumber