ReactJS: Kedalaman pembaruan maksimum melebihi kesalahan

177

Saya mencoba untuk beralih keadaan komponen di ReactJS tetapi saya mendapatkan kesalahan yang menyatakan:

Kedalaman pembaruan maksimum terlampaui. Ini bisa terjadi ketika suatu komponen berulang kali memanggil setState di dalam componentWillUpdate atau componentDidUpdate. React membatasi jumlah pembaruan bersarang untuk mencegah loop tak terbatas.

Saya tidak melihat loop tak terbatas dalam kode saya, adakah yang bisa membantu?

Kode komponen ReactJS:

import React, { Component } from 'react';
import styled from 'styled-components';

class Item extends React.Component {
    constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  
    toggle(){
        const currentState = this.state.details;
        this.setState({ details: !currentState }); 
    }

    render() {
        return (
            <tr className="Item"> 
                <td>{this.props.config.server}</td>      
                <td>{this.props.config.verbose}</td> 
                <td>{this.props.config.type}</td>
                <td className={this.state.details ? "visible" : "hidden"}>PLACEHOLDER MORE INFO</td>
                {<td><span onClick={this.toggle()}>Details</span></td>}
            </tr>
    )}
}

export default Item;
Maja Okholm
sumber
35
Ubah this.toggle()ke this.toggleatau{()=> this.toggle()}
pelajar
8
Perbaikan lain, meskipun tidak terkait dengan masalah Anda: Belok toggle(){...}ke toggle = () => {...}sehingga Anda tidak perlu binditu!
Berry M.
Terima kasih @learner. Anda membantu saya juga. Tolong jelaskan alasan di balik solusi Anda. Apa perbedaan keduanya?
Shamim
2
@Hamim Ini perbedaan antara memanggil fungsi yang ada, dan meneruskan referensi ke fungsi. Sangat membantu untuk memahami bahwa kami menulis kode untuk ditampilkan dan dipicu ketika pengguna melakukan sesuatu, bukan kode yang akan dipicu segera setelah pengguna memuat halaman. reactjs.org/docs/faq-functions.html
DisplayName

Jawaban:

274

itu karena Anda memanggil toggle di dalam metode render yang akan menyebabkan render dan toggle akan memanggil lagi dan merender ulang lagi dan seterusnya

baris ini di kode Anda

{<td><span onClick={this.toggle()}>Details</span></td>}

Anda perlu onClickmerujuk untuk this.toggletidak memanggilnya

untuk memperbaiki masalah lakukan ini

{<td><span onClick={this.toggle}>Details</span></td>}
Ali
sumber
8
Saya menghadapi situasi yang sama, tetapi saya harus melewati parameter untuk beralih, bagaimana hal ini dapat dilakukan?
Niveditha Karmegam
58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Ini tidak akan menyala dengan segera (dan rerender). Ini adalah definisi panggilan balik (fungsi panah).
Fabian Picone
15
@FabianPicone mencoba metode Anda, tetapi ketika saya console.log itu menunjukkan bahwa "param" dilewatkan sebagai acara, sebenarnya harus dilakukanonClick={() => this.toggle(param)}
iWillGetBetter
6
@ iWillGetBetter Ya param pertama di onClick adalah event klik. Jika Anda membutuhkan param tambahan, Anda juga dapat meneruskannya onClick={(event) => this.toggle(event, myParam)}.
Fabian Picone
1
Saya memiliki fungsi ini. closeEditModal = () => this.setState({openEditModal: false});Bagaimana menyebutnya dalam render?
Nux
31

Anda harus melewati objek acara saat memanggil fungsi:

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

Jika Anda tidak perlu menangani acara onClick, Anda juga dapat mengetik:

{<td><span onClick={(e) => this.toggle()}>Details</span></td>}

Sekarang Anda juga dapat menambahkan parameter Anda di dalam fungsi.

Florent Philippe
sumber
2
Objek acara secara otomatis dikirim jika tidak ada yang ditentukan. Cukup sertakan parameter input dalam fungsi yang disebut.
Jeff Pinkston
2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}melakukan trik untuk saya
iWillGetBetter
22

Lupakan reaksi terlebih dahulu:
Ini tidak terkait dengan bereaksi dan mari kita memahami konsep dasar Java Script. Misalnya, Anda telah menulis fungsi berikut dalam skrip java (nama adalah A).

function a() {

};

Q.1) Bagaimana cara memanggil fungsi yang telah kita definisikan?
Jawab: a ();

Q.2) Bagaimana cara melewati referensi fungsi sehingga kita bisa menyebutnya yang terakhir?
Jawab: biarkan kesenangan = a;

Sekarang datang ke pertanyaan Anda, Anda telah menggunakan paranthesis dengan nama fungsi, artinya fungsi tersebut akan dipanggil ketika pernyataan berikut akan ditampilkan.

<td><span onClick={this.toggle()}>Details</span></td>

Lalu Bagaimana cara memperbaikinya?
Sederhana!! Hapus saja tanda kurung. Dengan cara ini Anda telah memberikan referensi fungsi tersebut ke acara onClick. Ini akan memanggil kembali fungsi Anda hanya ketika komponen Anda diklik.

 <td><span onClick={this.toggle}>Details</span></td>

Satu saran yang dirilis untuk bereaksi:
Hindari menggunakan fungsi sebaris seperti yang disarankan oleh seseorang dalam jawaban, itu dapat menyebabkan masalah kinerja. Hindari kode berikut, Ini akan membuat instance dari fungsi yang sama lagi dan lagi setiap kali fungsi akan dipanggil (pernyataan lamda membuat instance baru setiap kali).
Catatan: dan tidak perlu meneruskan acara (e) secara eksplisit ke fungsi. Anda dapat mengaksesnya dalam fungsi tanpa melewatinya.

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578

Piyush N
sumber
6

Saya tahu ini memiliki banyak jawaban tetapi karena kebanyakan dari mereka sudah tua (yah, lebih tua), tidak ada yang menyebutkan pendekatan saya tumbuh sangat cepat. Pendeknya:

Gunakan komponen dan kait fungsional .

Lebih lama:

Cobalah untuk menggunakan komponen fungsional sebanyak yang bukan kelas terutama untuk rendering , DAN mencoba untuk menjaga mereka semurni mungkin (ya, data kotor secara default saya tahu).

Dua manfaat komponen fungsional yang jelas (ada lebih banyak):

  • Pureness atau near pureness membuat proses debug jadi lebih mudah
  • Komponen fungsional menghilangkan kebutuhan untuk kode boiler konstruktor

Bukti cepat untuk poin 2 - Bukankah ini benar-benar menjijikkan?

constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  

Jika Anda menggunakan komponen fungsional untuk lebih dari rendering Anda akan membutuhkan bagian kedua dari duo - hooks. Mengapa mereka lebih baik daripada metode siklus hidup, apa lagi yang bisa mereka lakukan dan lebih banyak lagi akan membutuhkan banyak ruang untuk saya bahas jadi saya sarankan Anda untuk mendengarkan pria itu sendiri: Dan mengkhotbahkan kaitnya

Dalam hal ini Anda hanya perlu dua kait:

Kait panggilan balik dengan mudah dinamai useCallback. Dengan cara ini Anda mencegah pengikatan fungsi berulang saat Anda membuat ulang.

State hook, disebut useState, untuk menjaga status meskipun seluruh komponen berfungsi dan mengeksekusi secara keseluruhan (ya, ini dimungkinkan karena keajaiban hooks). Di dalam kait itu Anda akan menyimpan nilai toggle.

Jika Anda membaca bagian ini Anda mungkin ingin melihat semua yang saya bicarakan dalam tindakan dan diterapkan pada masalah asli. Ini dia: Demo

Bagi Anda yang hanya ingin melihat-lihat komponen dan WTF tentang ini, di sini Anda:

const Item = () => {

    // HOOKZ
  const [isVisible, setIsVisible] = React.useState('hidden');

  const toggle = React.useCallback(() => {
    setIsVisible(isVisible === 'visible' ? 'hidden': 'visible');
  }, [isVisible, setIsVisible]);

    // RENDER
  return (
  <React.Fragment>
    <div style={{visibility: isVisible}}>
        PLACEHOLDER MORE INFO
    </div>
    <button onClick={toggle}>Details</button>
  </React.Fragment>
  )
};

PS: Saya menulis ini kalau-kalau banyak orang mendarat di sini dengan masalah yang sama. Semoga mereka akan menyukai apa yang mereka lihat setidaknya cukup baik untuk google sedikit lebih. Ini bukan saya mengatakan jawaban lain salah, ini saya mengatakan bahwa sejak saat mereka ditulis, ada cara lain (IMHO, yang lebih baik) dalam menangani ini.

DanteTheSmith
sumber
5

jika Anda tidak perlu meneruskan argumen agar berfungsi, cukup hapus () dari fungsi seperti di bawah ini:

<td><span onClick={this.toggle}>Details</span></td>

tetapi jika Anda ingin memberikan argumen, Anda harus melakukannya seperti di bawah ini:

<td><span onClick={(e) => this.toggle(e,arg1,arg2)}>Details</span></td>
Abolfazl Miadian
sumber
3

ReactJS: Kedalaman pembaruan maksimum melebihi kesalahan

inputDigit(digit){
  this.setState({
    displayValue: String(digit)
  })

<button type="button"onClick={this.inputDigit(0)}>

kenapa begitu

<button type="button"onClick={() => this.inputDigit(1)}>1</button>

Fungsi onDigit menetapkan negara, yang menyebabkan rerender, yang menyebabkan onDigit untuk memecat karena itulah nilai yang Anda tetapkan sebagai onClick yang menyebabkan negara diatur yang menyebabkan rerender, yang menyebabkan onDigit menyala karena itulah nilai yang Anda ' re… Etc

Rizo
sumber
3

1.Jika kita ingin meneruskan argumen dalam panggilan maka kita perlu memanggil metode seperti di bawah ini. Karena kita menggunakan fungsi panah, tidak perlu untuk mengikat metode cunstructor.

onClick={() => this.save(id)} 

ketika kita mengikat metode dalam konstruktor seperti ini

this.save= this.save.bind(this);

maka kita perlu memanggil metode tanpa melewati argumen seperti di bawah ini

onClick={this.save}

dan kami mencoba untuk menyampaikan argumen sambil memanggil fungsi seperti yang ditunjukkan di bawah ini kemudian muncul kesalahan seperti kedalaman maksimum terlampaui.

 onClick={this.save(id)}
Aplikasi Luar Biasa
sumber
1

onClick Anda harus memanggil fungsi, yang disebut toggle fungsi Anda.

onClick={() => this.toggle()}

makkagru
sumber
1

Dalam hal ini, kode ini

{<td><span onClick={this.toggle()}>Details</span></td>}

menyebabkan fungsi toggle untuk memanggil segera dan merendernya lagi dan lagi sehingga membuat panggilan tak terbatas.

jadi hanya meneruskan referensi ke metode sakelar itu akan menyelesaikan masalah.

jadi,

{<td><span onClick={this.toggle}>Details</span></td>}

akan menjadi kode solusi.

Jika Anda ingin menggunakan (), Anda harus menggunakan fungsi panah seperti ini

{<td><span onClick={()=> this.toggle()}>Details</span></td>}

Jika Anda ingin melewatkan parameter, Anda harus memilih opsi terakhir dan Anda dapat melewatkan parameter seperti ini

{<td><span onClick={(arg)=>this.toggle(arg)}>Details</span></td>}

Dalam kasus terakhir itu tidak memanggil segera dan tidak menyebabkan kembali membuat fungsi, maka menghindari panggilan tak terbatas.

Badri Paudel
sumber