ReactJS: Максимальна глибина оновлення перевищена помилка


178

Я намагаюся переключити стан компонента в ReactJS, але я отримую помилку, вказуючи:

Максимальна глибина оновлення перевищена. Це може статися, коли компонент багаторазово викликає setState всередині компонентаWillUpdate або компонентDidUpdate. Реакція обмежує кількість вкладених оновлень, щоб запобігти нескінченним циклам.

Я не бачу нескінченного циклу в своєму коді, хтось може допомогти?

Код компонента 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;

35
Перейти this.toggle()на this.toggleабо{()=> this.toggle()}
учень

8
Ще одне вдосконалення, хоч і не пов’язане з вашою проблемою: перетворіться toggle(){...}на них, toggle = () => {...}щоб вам не потрібно bind!
Беррі М.

Дякую @learner. Ви мені теж допомогли. Ви б ласкаво пояснили причину свого рішення. Яка різниця між цими двома?
Шамім

2
@Shamim Це різниця між викликом існуючої функції та передачею посилання на функцію. Корисно зрозуміти, що ми пишемо код, який відображається та спрацьовує, коли користувач щось робить, а не код, який потрібно запускати, як тільки користувач завантажує сторінку. reactjs.org/docs/faq-functions.html
DisplayName

Відповіді:


274

що через те, що ви викликаєте тумблер всередині методу візуалізації, що призведе до повторного візуалізації та перемикання, знову зателефонує та знову відтвориться тощо

цей рядок за вашим кодом

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

вам потрібно onClickзвернутися до того, щоб this.toggleне дзвонити

щоб вирішити проблему, зробіть це

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

9
Я стикаюся з подібною ситуацією, але мені потрібно передати параметр для переключення, як це можна зробити?
Ніведіта Кармегам

58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Це не вистрілить негайно (і повторно). Це визначення зворотного дзвінка (функція стрілки).
Фабіан Піконе

16
@FabianPicone спробував ваш метод, але коли я console.log показує, що "парам" був переданий як подія, насправді повинен зробитиonClick={() => this.toggle(param)}
iWillGetBetter

6
@iWillGetBetter Так, перший парам у onClick - це подія клацання. Якщо вам потрібен додатковий парам, ви можете також здати його onClick={(event) => this.toggle(event, myParam)}.
Фабіан Піконе

1
У мене є ця функція closeEditModal = () => this.setState({openEditModal: false});Як викликати її у візуалізації?
Nux

31

Ви повинні передавати об'єкт події під час виклику функції:

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

Якщо вам не потрібно обробляти подію onClick, ви також можете ввести:

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

Тепер ви також можете додати свої параметри в межах функції.


2
Об'єкт події автоматично надсилається, якщо нічого не вказано. Просто включіть вхідний параметр у функцію, яка викликається.
Джефф Пінкстон

2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}робить трюк для мене
iWillGetBetter

22

Спочатку забудьте про реагування:
це не пов’язано з реагуванням, а давайте зрозуміємо основні поняття Java Script. Для прикладу ви написали наступну функцію в сценарії java (ім'я A).

function a() {

};

Q.1) Як викликати визначену нами функцію?
Відповідь: a ();

Q.2) Як передати посилання на функцію, щоб ми могли назвати її останньою?
Відповідь: нехай весело = a;

Тепер, підходячи до вашого запитання, ви використовували парантез з назвою функції, значить, ця функція буде викликана, коли наступне твердження буде надано.

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

Тоді Як це виправити?
Просто !! Просто видаліть дужки. Таким чином, ви дали посилання на цю функцію onClick події. Він передзвонить вашу функцію лише тоді, коли натиснеться ваш компонент.

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

Одне пропозиція відхилилося відреагувати:
уникайте використання вбудованої функції, як запропонував хтось у відповідях, це може спричинити проблеми з продуктивністю. Уникайте наступного коду, він створюватиме екземпляр однієї і тієї ж функції знову і знову, коли буде викликана функція (оператор lamda створює новий екземпляр кожен раз).
Примітка: і немає потреби передавати події (e) явно функції. Ви можете отримати доступ до нього у функції, не передаючи її.

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

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


6

Я знаю, що на це є безліч відповідей, але оскільки більшість з них є старими (ну, старшими), жоден не згадує про підхід, для якого я дуже швидко зростаю. Коротко:

Використовуйте функціональні компоненти та гачки .

Більше:

Постарайтеся використовувати якнайбільше функціональних компонентів замість класових, особливо для візуалізації , І намагайтеся зберегти їх максимально чистими (так, дані за замовчуванням я знаю).

Дві прямо очевидні переваги функціональних компонентів (їх більше):

  • Чистота чи близькість до чистоти робить налагодження набагато простішим
  • Функціональні компоненти усувають необхідність коду конструкторського котла

Швидкий доказ для другої точки - Хіба це не зовсім огидно?

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

Якщо ви більше використовуєте функціональні компоненти, то для рендерінгу вам знадобиться друга частина великого дуету. Чому вони кращі, ніж методи життєвого циклу, що ще вони можуть зробити та багато іншого, знадобиться мені багато місця для висвітлення, тому я рекомендую вам послухати самого чоловіка: Ден проповідує гачки.

У цьому випадку вам потрібно лише два гачки:

Гак зворотного дзвінка, зручно названий useCallback. Таким чином ви перешкоджаєте прив'язці функції знову і знову під час повторного відтворення.

Державний гак, що називається useState, для збереження стану, незважаючи на те, що весь компонент функціонує та виконує у повному обсязі (так, це можливо завдяки магії гачків). Всередині цього гака ви будете зберігати значення toggle.

Якщо ви прочитаєте цю частину, ви, ймовірно, хочете побачити все, про що я говорив, на ділі і застосовано до оригінальної проблеми. Ось вам: Демо

Для тих із вас, хто хоче лише переглянути компонент і WTF - це ось що, ось ви:

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: Я написав це на випадок, якщо багато людей приземлилися тут із подібною проблемою. Сподіваємось, їм сподобається те, що вони бачать принаймні досить добре, щоб трохи більше погуглювати його. Це я не кажу, що інші відповіді невірні, це я кажу, що з моменту їх написання існує інший спосіб (IMHO, кращий) вирішення цього питання.


5

якщо вам не потрібно передавати аргументи для функціонування, просто видаліть () з функції, як показано нижче:

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

але якщо ви хочете передати аргументи, вам слід зробити наступне:

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

3

ReactJS: Максимальна глибина оновлення перевищена помилка

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

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

чому це?

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

Функція onDigit встановлює стан, що викликає повторну рендерінг, що призводить до того, що OnDigit запускає, оскільки це значення, яке ви встановлюєте як onClick, яке встановлює стан, яке викликає повторну рендерінг, а це призводить до того, що OnDigit запускає, оскільки це значення, яке ви ' повторно… і т.д.


3

1.Якщо ми хочемо передати аргумент у виклику, тоді нам потрібно викликати метод, як показано нижче. Оскільки ми використовуємо функції зі стрілками, не потрібно прив'язувати метод cunstructor.

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

коли ми зв'язуємо метод у конструкторі так

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

тоді нам потрібно викликати метод, не передаючи жодного аргументу, як показано нижче

onClick={this.save}

і ми намагаємося передавати аргумент під час виклику функції, як показано нижче, тоді помилка наближається до максимальної глибини.

 onClick={this.save(id)}

1

onClick ви повинні викликати функцію, яка називається перемиканням вашої функції.

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


1

У цьому випадку цей код

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

викликає функцію тумблеру негайно викликати та повторювати її знову і знову, таким чином здійснюючи нескінченні виклики.

тому передача лише посилання на цей метод перемикання вирішить проблему.

так ,

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

буде кодом рішення.

Якщо ви хочете використовувати (), вам слід скористатися такою функцією зі стрілкою

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

У випадку, якщо ви хочете передавати параметри, вам слід вибрати останній варіант, і ви можете передавати такі параметри

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

В останньому випадку він не викликає відразу та не викликає відтворення функції, отже, уникаючи нескінченних дзвінків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.