Bereaksi: mengapa komponen anak tidak diperbarui ketika prop berubah

135

Mengapa dalam contoh pseudo-code berikut, Child tidak merender ulang ketika Container berubah foo.bar?

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

Bahkan jika saya menelepon forceUpdate()setelah mengubah nilai dalam Container, Child masih menunjukkan nilai lama.

Tuomas Toivonen
sumber
5
Apakah ini kode Anda? Sepertinya itu bukan kode Bereaksi yang valid
Saya pikir nilai alat peraga tidak boleh berubah dalam komponen wadah melainkan harus diubah dalam komponen induk oleh setState dan bahwa negara harus memetakan ke alat peraga kontainer
Piyush Patel
Gunakan operator sebar seperti ini <Bar anak = {... this.props.foo.bar} />
Sourav Singh
@AdrianWydmanski dan 5 orang lainnya yang terpilih: en.wikipedia.org/wiki/Pseudocode
David Newcomb
@PiyushPatel props dimutakhirkan ketika sebuah komponen di-render ulang di tempat seperti contoh pseudo-code. Contoh lain dari ini adalah dengan sesuatu seperti menggunakan <Route exact path="/user/:email" component={ListUserMessagePage} />, tautan pada halaman yang sama akan memperbarui alat peraga tanpa membuat instance baru dan menjalankan peristiwa siklus hidup yang biasa.
David Newcomb

Jawaban:

94

Perbarui anak untuk memiliki atribut 'kunci' sama dengan nama. Komponen akan merender ulang setiap kali kunci berubah.

Child {
  render() {
    return <div key={this.props.bar}>{this.props.bar}</div>
  }
}
polina-c
sumber
5
Terima kasih untuk ini. Saya menggunakan redux store dan komponen saya tidak bisa merender ulang sampai saya menambahkan kunci. (Saya menggunakan pustaka uuid untuk menghasilkan kunci acak, dan itu berhasil).
Maiya
Dengan menggunakan kait, anak saya tidak akan merender ulang ketika mengatur status pada array yang ada. Saya (ide mungkin buruk) hack adalah untuk secara bersamaan mengatur keadaan dummy prop dan menambahkan bahwa untuk useEffect ketergantungan array yang: [props.notRenderingArr, props.dummy]. Jika panjang array selalu berubah, Anda bisa mengatur array dependensi useEffect [props.notRenderingArr.length].
hipnosis
5
inilah yang saya butuhkan juga. Saya bingung, kapan keyharus, vs adil setState? Saya punya beberapa anak yang mengandalkan keadaan orang tua tetapi mereka tidak memicu re-render ...
dcsan
Jawaban yang bagus Tetapi mengapa perilaku ini?
Rishav
1
Saya menggunakan indeks sebagai kunci tetapi tidak berfungsi dengan baik. Sekarang saya menggunakan uuid dan sempurna :) Terima kasih kepada @ Maiya
Ali Rehman
90

Karena anak-anak tidak rerender jika alat peraga orang tua berubah, tetapi jika NEGARA nya berubah :)

Apa yang Anda perlihatkan adalah ini: https://facebook.github.io/react/tips/communicate-between-components.html

Ini akan meneruskan data dari orangtua ke anak melalui alat peraga tetapi tidak ada logika rerender di sana.

Anda perlu mengatur beberapa status ke orangtua lalu rerender anak pada status perubahan orangtua. Ini bisa membantu. https://facebook.github.io/react/tips/expose-component-functions.html

François Richard
sumber
5
Mengapa setState akan menyebabkan render ulang tetapi forceUpdate tidak? Juga sedikit dari topik, tetapi bagaimana komponen diperbarui ketika props disahkan dari redux dan statusnya diperbarui melalui tindakan?
Tuomas Toivonen
alat peraga tidak diperbarui bahkan jika Anda memperbarui komponen alat peraga yang Anda lewati masih ada. Fluks adalah topik lain ya :)
François Richard
3
state! = alat peraga yang perlu Anda baca lebih lanjut tentang itu. Anda tidak membuat pembaruan dengan alat peraga
François Richard
Anda dapat melihatnya secara langsung dalam kode sumber, itu bukan proses yang sama
Webwoman
jadi apa yang Anda katakan di sini telah diubah atau saya tidak memahaminya dengan benar, saya mengajukan pertanyaan untuk itu, stackoverflow.com/questions/58903921/…
ILoveReactAndNode
51

Saya memiliki masalah yang sama. Ini solusi saya, saya tidak yakin itu adalah praktik yang baik, beri tahu saya jika tidak:

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD: Sekarang Anda dapat melakukan hal yang sama menggunakan React Hooks: (hanya jika komponen berfungsi)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);
petrichor
sumber
3
Ini jelas merupakan jawaban yang benar, belum lagi yang paling sederhana
Guilherme Ferreira
1
Saya juga menggunakan pendekatan ini.
mentah
@ vancy-celana The componentDidUpdatedalam hal ini masuk dalam komponen Anak.
Nick Friskel
4
Anda tidak perlu dan tidak boleh mengubah alat peraga untuk menyatakan dalam komponen anak. Cukup gunakan alat peraga secara langsung. Di FunctionComponentsdalamnya akan secara otomatis memperbarui komponen anak jika alat peraga berubah.
oemera
1
Pendekatan ini juga berfungsi ketika Anda memiliki alat peraga dalam komponen anak yang berasal dari negara induk
Chefk5
10

Menurut komponen filosofi React tidak dapat mengubah alat peraga. mereka harus diterima dari orang tua dan harus tidak berubah. Hanya orang tua yang dapat mengubah properti anak-anaknya.

penjelasan bagus tentang negara vs alat peraga

juga, baca utas ini. Mengapa saya tidak dapat memperbarui alat peraga di react.js?

Sujan Thakare
sumber
Bukankah ini juga berarti bahwa wadah tidak dapat memodifikasi alat peraga yang diterimanya dari toko redux?
Tuomas Toivonen
3
Kontainer tidak menerima alat peraga langsung dari toko, mereka dipasok dengan membaca bagian dari pohon redux state (membingungkan ??). !! kebingungan adalah karena kita tidak tahu tentang fungsi magis terhubung dengan react-redux. jika Anda melihat kode sumber metode connect, pada dasarnya ia menciptakan komponen urutan yang lebih tinggi yang memiliki keadaan dengan storeState properti dan berlangganan ke toko redux. sebagai storeState mengubah seluruh rendering ulang terjadi, dan alat peraga yang dimodifikasi disuplai ke wadah dengan membaca keadaan yang diubah. harap ini menjawab pertanyaan
Sujan Thakare
Penjelasan yang baik, memikirkan komponen tingkat tinggi membantu saya memahami apa yang terjadi
Tuomas Toivonen
7

Anda harus menggunakan setStatefungsi. Jika tidak, nyatakan tidak akan menyimpan perubahan Anda, tidak peduli bagaimana Anda menggunakan forceUpdate.

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{this.props.bar}</div>
        }
    }
}

Kode Anda sepertinya tidak valid. Saya tidak dapat menguji kode ini.

James Yin
sumber
Bukankah seharusnya begitu <Child bar={this.state.foo.bar} />?
Josh Broadhurst
Baik. Saya memperbarui jawabannya. Tapi seperti yang saya katakan ini mungkin bukan kode yang valid. Cukup salin dari pertanyaan.
JamesYin
5

Saat membuat komponen Bereaksi dari functionsdan useState.

const [drawerState, setDrawerState] = useState(false);

const toggleDrawer = () => {
      // attempting to trigger re-render
      setDrawerState(!drawerState);
};

Ini tidak bekerja

         <Drawer
            drawerState={drawerState}
            toggleDrawer={toggleDrawer}
         />

Ini bekerja (menambahkan kunci)

         <Drawer
            drawerState={drawerState}
            key={drawerState}
            toggleDrawer={toggleDrawer}
         />
Nelles
sumber
3

Dikonfirmasi, menambahkan Kunci berfungsi. Saya membaca dokumen untuk mencoba dan memahami mengapa.

Bereaksi ingin menjadi efisien ketika membuat komponen anak. Itu tidak akan membuat komponen baru jika itu sama dengan anak lain, yang membuat halaman memuat lebih cepat.

Menambahkan kekuatan kunci Bereaksi untuk membuat komponen baru, sehingga mengatur ulang status untuk komponen baru itu.

https://reactjs.org/docs/reconciliation.html#recursing-on-children

tjr226
sumber
2

Gunakan fungsi setState. Jadi kamu bisa melakukannya

       this.setState({this.state.foo.bar:123}) 

di dalam metode pegangan acara.

Setelah, negara diperbarui, itu akan memicu perubahan, dan render ulang akan terjadi.

Indraneel Bende
sumber
1
Seharusnya this.setState ({foo.bar:123}) benar?
Charith Jayasanka
0

Anda mungkin harus menjadikan Anak sebagai komponen fungsional jika tidak mempertahankan status apa pun dan cukup membuat alat peraga lalu memanggilnya dari induknya. Alternatif untuk ini adalah bahwa Anda dapat menggunakan kait dengan komponen fungsional (useState) yang akan menyebabkan komponen stateless kembali di-render.

Anda juga sebaiknya tidak mengubah propa karena tidak dapat diubah. Pertahankan status komponen.

Child = ({bar}) => (bar);
satyam soni
sumber
0

Saya mengalami masalah yang sama. Saya memiliki Tooltipkomponen yang menerima showTooltipprop, bahwa saya memperbarui pada Parentkomponen berdasarkan suatu ifkondisi, Parentkomponen itu semakin diperbarui tetapi Tooltipkomponen tidak merender.

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      <Tooltip showTooltip={showTooltip}></Tooltip>
   )
}

Kesalahan yang saya lakukan adalah menyatakan showTooltipsebagai let.

Saya menyadari apa yang saya lakukan salah saya melanggar prinsip-prinsip bagaimana rendering bekerja, Menggantinya dengan kait melakukan pekerjaan.

const [showTooltip, setShowTooltip] =  React.useState<boolean>(false);
Divyanshu Rawat
sumber
0

mendefinisikan alat peraga yang diubah di mapStateToProps metode koneksi dalam komponen anak.

function mapStateToProps(state) {
  return {
    chanelList: state.messaging.chanelList,
  };
}

export default connect(mapStateToProps)(ChannelItem);

Dalam kasus saya, saluran channelList diperbarui jadi saya menambahkan chanelList di mapStateToProps

Rajesh Nasit
sumber
0
export default function DataTable({ col, row }) {
  const [datatable, setDatatable] = React.useState({});
  useEffect(() => {
    setDatatable({
      columns: col,
      rows: row,
    });
  /// do any thing else 
  }, [row]);

  return (
    <MDBDataTableV5
      hover
      entriesOptions={[5, 20, 25]}
      entries={5}
      pagesAmount={4}
      data={datatable}
    />
  );
}

contoh ini digunakan useEffectuntuk mengubah status saat propsperubahan.

ibrahim alsimiry
sumber