ReactJS: Maksimum güncelleme derinliği aşıldı hatası


178

ReactJS bir bileşenin durumunu değiştirmeye çalışıyorum ama belirten bir hata alıyorum:

Maksimum güncelleme derinliği aşıldı. Bu, bir bileşen defalarca componentWillUpdate veya componentDidUpdate içinde setState öğesini çağırdığında meydana gelebilir. Reaksiyon, sonsuz döngüleri önlemek için iç içe güncellemelerin sayısını sınırlar.

Kodumda sonsuz döngü görmüyorum, kimse yardımcı olabilir mi?

ReactJS bileşen kodu:

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;

35
Değişim this.toggle()için this.toggleya{()=> this.toggle()}
öğrenen

8
Diğer bir gelişme, sizin sorunuyla ilgisi olsa: çevirin toggle(){...}içine toggle = () => {...}yapmanız gerek kalmaz bindo!
Berry M.

Teşekkürler @learner. Bana da yardım ettin. Çözümünüzün nedenini açıklar mısınız? Bu ikisi arasındaki fark nedir?
Shamim

2
@Shamim Varolan bir işlevi çağırmak ve başvuruyu bir işleve geçirmek arasındaki farktır. Kullanıcı sayfayı yükler yüklemez tetiklenecek kodu değil, kullanıcı bir şey yaptığında görüntülenecek ve tetiklenecek kod yazdığımızı anlamak faydalı olacaktır. reaktjs.org/docs/faq-functions.html
DisplayName

Yanıtlar:


274

çünkü yeniden oluşturma ve açma işlemine neden olacak oluşturma yönteminin içinde geçiş yapmayı çağırdığınızda, tekrar çağrılacak ve yeniden oluşturuluyor vb.

kodunuzdaki bu satır

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

Yapmanız gereken onClickbakın this.togglebunu aramıyor

için düzeltmek sorunu Bunu yapmak

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

9
Benzer bir durumla karşı karşıyayım, ancak geçiş yapmak için bir parametre geçmem gerekiyor, bu nasıl yapılabilir?
Niveditha Karmegam

58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Bu derhal ateşlenmeyecek (ve tekrar ortaya çıkacaktır). Bu bir geri arama tanımıdır (ok işlevi).
Fabian Picone

16
@FabianPicone yönteminizi denedi ama i console.log olay olarak "param" geçti olduğunu gösterir, aslındaonClick={() => this.toggle(param)}
iWillGetBetter 31:18

6
@iWillGetBetter Evet onClick'teki ilk parametre tıklama olayıdır. Ek bir parametreye ihtiyacınız varsa bunu da geçebilirsiniz onClick={(event) => this.toggle(event, myParam)}.
Fabian Picone

1
Ben bu işlevi var closeEditModal = () => this.setState({openEditModal: false});Nasıl render denir?
Nux

31

İşlevi çağırırken olay nesnesini iletmeniz gerekir:

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

OnClick olayını işlemeniz gerekmiyorsa şunları da yazabilirsiniz:

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

Artık işlevlerinize parametrelerinizi de ekleyebilirsiniz.


2
Hiçbir şey belirtilmezse olay nesnesi otomatik olarak gönderilir. Sadece çağrılan işleve bir girdi parametresi ekleyin.
Jeff Pinkston

2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}benim için hile yapar
iWillGetBetter

22

İlk önce reaksiyonu unutun:
Bu, reaksiyonla ilgili değildir ve Java Script'in temel kavramlarını anlamamıza izin verir. Örneğin, java komut dosyasına aşağıdaki işlevi yazdınız (ad A'dır).

function a() {

};

S.1) Tanımladığımız fonksiyon nasıl çağırılır?
Ans: a ();

S.2) Fonksiyonun referansını nasıl geçebiliriz, böylece onu daha sonra çağırabiliriz?
Ans: eğlence olsun = a;

Şimdi sorunuza gelince, işlev adı ile parantez kullandınız, yani aşağıdaki ifade oluşturulduğunda işlev çağırılacaktır.

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

O zaman nasıl düzeltilir?
Basit!! Parantezi kaldırmanız yeterlidir. Bu şekilde, bu işlevin onClick olayına referansını verdiniz. Yalnızca bileşeniniz tıklandığında işlevinizi geri çağırır.

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

Tepki vermekle ilgili bir öneri:
Yanıtlarda birisi tarafından önerilen satır içi işlevi kullanmaktan kaçının, performans sorununa neden olabilir. Kodu izlemekten kaçının, işlev çağrıldığında aynı işlevin örneğini tekrar tekrar oluşturur (lamda deyimi her seferinde yeni örnek oluşturur).
Not: ve (e) olayını açıkça işleve geçirmeye gerek yoktur. fonksiyondan geçmeden ona erişebilirsiniz.

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

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


6

Bunun çok fazla cevabı olduğunu biliyorum ama çoğu eski (iyi, yaşlı) olduğu için hiçbiri gerçekten çok hızlı büyüdüğüm yaklaşımdan bahsetmiyor. Kısacası:

Fonksiyonel bileşenler ve kancalar kullanın .

Daha uzun süre:

Özellikle render için sınıf yerine fonksiyonel bileşenleri kullanmaya çalışın ve bunları mümkün olduğunca saf tutmaya çalışın (evet, varsayılan olarak veri kirli).

Fonksiyonel bileşenlerin açıkça görülmeyen iki faydası (daha fazlası var):

  • Saflık veya neredeyse saflık, hata ayıklamayı çok daha kolay hale getirir
  • Fonksiyonel bileşenler, yapıcı kazan kodu ihtiyacını ortadan kaldırır

2. puan için hızlı kanıt - Bu kesinlikle iğrenç değil mi?

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

Daha fazlasını oluşturmak için fonksiyonel bileşenler kullanıyorsanız, büyük ikili kancaların ikinci kısmına ihtiyacınız olacak. Neden yaşam döngüsü yöntemlerinden daha iyidirler, başka ne yapabilirler ve çok daha fazlası beni kapsayacak çok yer kaplar, bu yüzden adamı kendiniz dinlemenizi öneririm: Dan kancaları vaaz ediyor

Bu durumda sadece iki kancaya ihtiyacınız vardır:

Uygun şekilde adlandırılmış bir geri çağırma kancası useCallback. Bu şekilde, yeniden oluşturduğunuzda işlevin tekrar tekrar bağlanmasını önlersiniz.

useStateTüm bileşenin işlev görmesine ve bütünüyle yürütülmesine rağmen durumu korumak için çağrılan bir durum kancası (evet, bu kancaların büyüsü nedeniyle mümkündür). Bu kancada geçişin değerini kaydedersiniz.

Bu bölümü okursanız muhtemelen konuştuğum her şeyi görmek ve orijinal soruna başvurmak istersiniz. Buyrun: Demo

Sadece bileşene göz atmak isteyen ve WTF bu konuda, işte buradasınız:

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>
  )
};

Not: Bunu birçok insanın buraya benzer bir problemle inmesi durumunda yazdım. İnşallah onlar en azından biraz daha google için yeterince iyi gördüklerini gibi olacaklar. Bu, diğer cevapların yanlış olduğunu söylemek değil, yazıldıkları zamandan beri bununla başa çıkmanın başka bir yolu (IMHO, daha iyi) olduğunu söylüyor.


5

işlev için bağımsız değişkenleri iletmeniz gerekmiyorsa, aşağıdaki gibi işlevden () öğesini kaldırmanız yeterlidir:

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

ancak argümanları iletmek istiyorsanız, aşağıdakileri yapmalısınız:

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

3

ReactJS: Maksimum güncelleme derinliği aşıldı hatası

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

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

neden bu?

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

OnDigit işlevi, bir yeniden göndericiye neden olan durumu ayarlar, bu da onDigit'in çalışmasına neden olur, çünkü onClick olarak ayarladığınız değer bu durumun ayarlanmasına neden olur, bu da bir yeniden gönderime neden olur, bu da onDigit'in çalışmasına neden olur çünkü re… vb.


3

Eğer çağrıda argüman iletmek istiyorsak, aşağıdaki gibi yöntemi çağırmalıyız cunstructor.

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

yöntemi böyle bir yapıcıya bağladığımızda

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

o zaman aşağıdaki gibi herhangi bir argüman geçirmeden yöntemi çağırmamız gerekir

onClick={this.save}

ve işlevi aşağıda gösterildiği gibi çağırırken argüman iletmeye çalışıyoruz, sonra hata maksimum derinlik aşılmış gibi geliyor.

 onClick={this.save(id)}

1

Fonksiyonu çağırmalısınız, fonksiyonunuz arasında geçiş denir.

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


1

Bu durumda, bu kod

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

açma / kapatma işlevinin hemen çağrılmasına ve tekrar tekrar görüntülenmesine ve böylece sonsuz çağrı yapılmasına neden olur.

bu nedenle, yalnızca bu geçiş yöntemine yapılan referansın iletilmesi sorunu çözecektir.

yani ,

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

çözüm kodu olacak.

() İşlevini kullanmak istiyorsanız, bunun gibi bir ok işlevi kullanmalısınız

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

Parametreleri geçmek istiyorsanız, son seçeneği seçmelisiniz ve bunun gibi parametreleri iletebilirsiniz

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

Son durumda, hemen çağırmaz ve işlevin yeniden oluşturulmasına neden olmaz, böylece sonsuz çağrıları önler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.