Bagaimana komponen yang terhubung dengan redux tahu kapan harus merender ulang?

94

Saya mungkin melewatkan sesuatu yang sangat jelas dan ingin membersihkan diri.

Berikut pemahaman saya.
Dalam komponen reaksi naif, kita memiliki states& props. Memperbarui statedengan setStatemerender ulang seluruh komponen. propskebanyakan hanya baca dan memperbaruinya tidak masuk akal.

Dalam komponen react yang berlangganan toko redux, melalui sesuatu seperti store.subscribe(render), itu jelas merender ulang setiap kali toko diperbarui.

react-redux memiliki helper connect()yang menyuntikkan bagian dari pohon status (yang menarik bagi komponen) dan actionCreators propske komponen, biasanya melalui sesuatu seperti

const TodoListComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

Tetapi dengan pemahaman bahwa a setStatesangat penting untuk TodoListComponentbereaksi terhadap perubahan pohon status redux (render ulang), saya tidak dapat menemukan kode apa pun stateatau setStateterkait dalam TodoListfile komponen. Bunyinya seperti ini:

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

Dapatkah seseorang mengarahkan saya ke arah yang benar tentang apa yang saya lewatkan?

PS Saya mengikuti contoh daftar rencana yang dibundel dengan paket redux .

Joe Lewis
sumber

Jawaban:

116

The connectFungsi menghasilkan komponen wrapper yang berlangganan ke toko. Saat suatu tindakan dikirim, callback komponen pembungkus akan diberi tahu. Kemudian menjalankan mapStatefungsi Anda , dan membandingkan dangkal objek hasil dari waktu ini vs objek hasil dari terakhir kali (jadi jika Anda menulis ulang bidang penyimpanan redux dengan nilai yang sama, itu tidak akan memicu render ulang). Jika hasilnya berbeda, maka hasilnya akan diteruskan ke "komponen" Anda yang sebenarnya sebagai properti.

Dan Abramov menulis versi sederhana yang bagus dari connectat ( connect.js ) yang menggambarkan ide dasar, meskipun tidak menunjukkan pekerjaan pengoptimalan apa pun. Saya juga memiliki tautan ke sejumlah artikel tentang kinerja Redux yang membahas beberapa ide terkait.

memperbarui

React-Redux v6.0.0 membuat beberapa perubahan internal utama tentang bagaimana komponen yang terhubung menerima datanya dari penyimpanan.

Sebagai bagian dari itu, saya menulis postingan yang menjelaskan cara kerja connectAPI dan internal, dan bagaimana mereka berubah seiring waktu:

Redux Idiomatik: Sejarah dan Implementasi React-Redux

markerikson
sumber
Terima kasih! Apakah Anda orang yang sama yang membantu saya tempo hari @ HN - news.ycombinator.com/item?id=12307621 dengan link yang berguna? Senang bertemu Anda :)
Joe Lewis
4
Yup, itulah aku :) Aku menghabiskan cara terlalu banyak waktu mencari diskusi Redux online - Reddit, HN, SO, Medium, dan berbagai tempat lainnya. Senang untuk membantu! (Juga untuk diketahui, saya sangat merekomendasikan saluran obrolan Reactiflux di Discord. Banyak orang nongkrong di sana dan menjawab pertanyaan. Saya biasanya online di sana malam hari US EST. Tautan undangan ada di reactiflux.com .)
markerikson
Dengan asumsi ini menjawab pertanyaan, keberatan menerima jawabannya? :)
markerikson
Apakah itu membandingkan objek itu sendiri atau properti dari objek sebelum / sesudah? Jika yang terakhir, apakah itu hanya memeriksa tingkat pertama, apakah itu yang Anda maksud dengan "dangkal?"
Andy
Ya, "kesetaraan cek dangkal" berarti untuk membandingkan bidang tingkat pertama dari setiap objek: prev.a === current.a && prev.b === current.b && ...... Itu mengasumsikan bahwa setiap perubahan data akan menghasilkan referensi baru, yang berarti pembaruan data yang tidak dapat diubah diperlukan alih-alih mutasi langsung.
markerikson
14

Jawaban saya sedikit keluar dari bidang kiri. Ini menjelaskan masalah yang membawa saya ke posting ini. Dalam kasus saya, tampaknya aplikasi tersebut Tidak merender ulang, meskipun menerima alat peraga baru.
React devs memiliki jawaban untuk pertanyaan yang sering ditanyakan ini, sesuatu yang sesuai jika (store) dimutasi, 99% dari waktu itulah alasan react tidak akan dirender ulang. Namun tidak ada tentang 1% lainnya. Mutasi tidak terjadi di sini.


TLDR;

componentWillReceivePropsadalah bagaimana statedapat tetap disinkronkan dengan yang baru props.

Tepi Kasus: Setelah stateupdate, maka aplikasi tidak re-render!


Ternyata jika aplikasi Anda hanya menggunakan stateuntuk menampilkan elemennya, propsdapat memperbarui, tetapi statetidak mau, jadi tidak ada render ulang.

Saya punya stateyang tergantung pada yang propsditerima dari redux store. Data yang saya butuhkan belum ada di toko, jadi saya mengambilnya componentDidMountsebagaimana mestinya. Saya mendapatkan propsnya kembali, ketika peredam saya memperbarui toko, karena komponen saya terhubung melalui mapStateToProps. Tetapi halaman tersebut tidak merender, dan statusnya masih penuh dengan string kosong.

Contohnya adalah pengguna memuat halaman "edit posting" dari url yang disimpan. Anda memiliki akses ke postIddari url, tetapi infonya belum masuk store, jadi Anda mengambilnya. Item di halaman Anda adalah komponen yang dikontrol - jadi semua data yang Anda tampilkan ada di dalamnya state.

Menggunakan redux, data diambil, penyimpanan diperbarui, dan komponen connectdiedit, tetapi aplikasi tidak mencerminkan perubahan. Dilihat lebih dekat, propsditerima, tetapi aplikasi tidak diperbarui. statetidak diperbarui.

Yah, propsakan memperbarui dan menyebarkan, tetapi statetidak. Anda perlu memberi tahu secara khusus stateuntuk memperbarui.

Anda tidak dapat melakukan ini render(), dan componentDidMountsudah menyelesaikan siklusnya.

componentWillReceivePropsadalah tempat Anda memperbarui stateproperti yang bergantung pada propnilai yang diubah .

Contoh Penggunaan:

componentWillReceiveProps(nextProps){
  if (this.props.post.category !== nextProps.post.category){
    this.setState({
      title: nextProps.post.title,
      body: nextProps.post.body,
      category: nextProps.post.category,
    })
  }      
}

Saya harus berteriak ke artikel ini yang mencerahkan saya tentang solusi yang gagal disebutkan oleh puluhan postingan, blog, dan repo lain. Siapa pun yang kesulitan menemukan jawaban untuk masalah yang jelas tidak jelas ini, Ini dia:

Metode siklus hidup komponen ReactJs - Menyelami lebih dalam

componentWillReceivePropsadalah tempat Anda akan memperbarui stateagar tetap sinkron dengan propspembaruan.

Setelah statediperbarui, kemudian bidang bergantung pada state lakukan render ulang!

SherylHohman
sumber
3
Dari React 16.3seterusnya, Anda harus menggunakan getDerivedStateFromPropsbukan componentWillReceiveProps. Tetapi pada kenyataannya, Anda seharusnya tidak melakukan semua itu seperti yang diartikulasikan di sini
kyw
tidak bekerja, setiap kali status berubah maka componentWillReceiveProps akan bekerja begitu banyak kasus saya coba ini tidak berhasil. Terutama, multi level bersarang atau props kompleks jadi saya harus menetapkan komponen dengan ID dan memicu perubahan untuk itu dan memperbarui status untuk merender ulang data baru
May'Habit
0

Jawaban ini merupakan ringkasan dari artikel Brian Vaughn yang berjudul You Probably Don't Need Derived State (07 Juni 2018).

Status berasal dari alat peraga adalah anti-pola dalam segala bentuknya. Termasuk menggunakan yang lebih lama componentWillReceivePropsdan yang lebih baru getDerivedStateFromProps.

Alih-alih mendapatkan status dari props, pertimbangkan solusi berikut.

Dua rekomendasi praktik terbaik

Rekomendasi 1. Komponen yang dikontrol sepenuhnya
function EmailInput(props) {
  return <input onChange={props.onChange} value={props.email} />;
}
Rekomendasi 2. Komponen yang sepenuhnya tidak terkontrol dengan kunci
// parent class
class EmailInput extends Component {
  state = { email: this.props.defaultEmail };

  handleChange = event => {
    this.setState({ email: event.target.value });
  };

  render() {
    return <input onChange={this.handleChange} value={this.state.email} />;
  }
}

// child instance
<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

Dua alternatif jika, karena alasan apa pun, rekomendasi tersebut tidak berhasil untuk situasi Anda.

Alternatif 1: Atur ulang komponen yang tidak terkontrol dengan ID prop
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail,
    prevPropsUserID: this.props.userID
  };

  static getDerivedStateFromProps(props, state) {
    // Any time the current user changes,
    // Reset any parts of state that are tied to that user.
    // In this simple example, that's just the email.
    if (props.userID !== state.prevPropsUserID) {
      return {
        prevPropsUserID: props.userID,
        email: props.defaultEmail
      };
    }
    return null;
  }

  // ...
}
Alternatif 2: Setel ulang komponen yang tidak terkontrol dengan metode instance
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail
  };

  resetEmailForNewUser(newEmail) {
    this.setState({ email: newEmail });
  }

  // ...
}
Biarkan Aku Memikirkannya
sumber
-2

karena saya hanya tahu hal yang dilakukan redux, pada perubahan status toko memanggil componentWillRecieveProps jika komponen Anda bergantung pada status mutasi dan kemudian Anda harus memaksa komponen Anda untuk memperbaruinya seperti ini

Perubahan status 1-toko-2-panggilan (componentWillRecieveProps (() => {3-component state change}))

ghazaleh javaheri
sumber