Реагировать на бесконечный цикл

Я новичок в React и прошу прощения за свой английский.

Когда я передаю данные из дочернего в родительский компонент и нажимаю другую кнопку, они не отображаются.

как вы можете видеть в моем комментарии, setState создает бесконечный цикл, останавливая возможность обновления значения.

Я пробовал разные способы решения проблемы, создавая внутренние переменные конструктора, такие как this.name = '' и this.selected = [], и устанавливая обратный вызов как this.name = name и this.selected = selected, но не отображается, когда я нажимаю другие параметры.

Я пробовал работать с componentDidMount() и другими методами жизненного цикла, но не знаю, как это решить.

App.js (родительский компонент)

state = { name: '', selected: [] };

doParentControl = (name, selected) => {
   console.info('doParentControl name: ',name);
   console.info('doParentControl selected: ',selected);
   // this.setState({ name: name, selected: selected }) --> infinite loop
}

render() {
   console.info('-> render App')
   return (
    <div className = "App">
      <header className = "App-header">
        <h1>Map</h1>
       </header>
       <div className = "Map">
         <Navbar parentControl = {this.doParentControl}/>
         <MapComponent name = {this.state.name} selected = {this.state.selected}/>
       </div>
       <div className = "clearfix" />
   </div>
   );
}

Navbar.js (Дочерний компонент)

constructor(props) {
    super(props);
    this.selected = [false, false, false];
    this.state = { name: 'tile' };
}

handleClick = (e) => {
    this.setState({name: e.target.value});
}

handleChangeEvent = (e) => {
    switch(e.target.value) {
        case 'option1': {
            this.setState({ selected: this.selected[0] = e.target.checked})
            break;
        }
        case 'option2': {
            this.setState({ selected: this.selected[1] = e.target.checked})        
            break;
        }
        case 'option3': {
            this.setState({ selected: this.selected[2] = e.target.checked})        
            break;
        }
        default:
            break;
    }
}

doParentControlFromChild = () => {
    this.props.parentControl(this.state.name, this.selected);
}

render() {
    console.info('render Navbar ->')
    return (
        <div className = "nav-bar">
            <nav className = "App-nav">
                <div className = "buttons">
                    <button name = "tile"        onClick = {this.handleClick} value = "tile">Tile</button>
                    <button name = "tile-watercolor" onClick = {this.handleClick} value = "tile-watercolor">Tile WaterColor</button>
                    <button name = "cartografia" onClick = {this.handleClick} value = "cartografia">Cartografía</button>
                    <button name = "satelite"    onClick = {this.handleClick} value = "satelite">Satélite</button>
                    <button name = "mapa"        onClick = {this.handleClick} value = "mapa">Mapa</button>
                </div>
                <div className = "clearfix"></div>
            </nav>
            <div className = "checkbox">
                <label><input type = "checkbox" name = "option1" value = "option1"  onChange = {this.handleChangeEvent} />Option 1</label>
                <label><input type = "checkbox" name = "option2" value = "option2"   onChange = {this.handleChangeEvent} />Option 2</label>
                <label><input type = "checkbox" name = "option3" value = "option3"      onChange = {this.handleChangeEvent} />Option 3</label>
            </div>
            <div className = "clearfix" />
            { this.doParentControlFromChild() }
        </div>
    );
}

спасибо Tomasz за редактирование текста

Javier 18.03.2018 14:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
2 084
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

{ this.doParentControlFromChild() } выполняет вызов функции при рендеринге, что вызывает изменение состояния, что вызывает повторный рендеринг, следовательно, ваш цикл. Избавьтесь от скобок и разрешите вызывать только функцию, вызывающую setState, из действия пользователя, а не просто вызов рендеринга. Что-то вроде этого подойдет:

<div className = "clearfix" onClick = {this.doParentControlFromChild}/>

Спасибо!! Я понимаю, что обратный вызов от ребенка должен быть внутри элемента html. medium.com/@ruthmpardee/… 1 - если я помещаю внутри clearfix только рендеринг дочернего элемента и не передаю данные родительскому 2 - overide onClick и handleClick не работает

Javier 18.03.2018 15:05
Ответ принят как подходящий

setState() позволяет render() выполнять повторный рендеринг. Итак, setState(), развернутый на doParentControl в родительском компоненте, вызывает повторную визуализацию компонента, а в вашем дочернем компоненте return( ... { this.doParentControlFromChild()} ... ) просто сопровождает визуализацию элементов. Это приводит к повторному вызову doParentControl из родительского компонента, поэтому здесь у нас есть бесконечный цикл. Как и в предыдущем ответе, вам нужно разрешить вызов doParentControlFromChild только тогда, когда это необходимо.

App.js (Father)
...
state = { name: '', selected: [] };

doParentControl = (name, selected) => {
   console.info('doParentControl name: ',name);
   console.info('doParentControl selected: ',selected);
   this.setState({ name: name, selected: selected })
}

render() {
   console.info('-> render App')
   return (
    <div className = "App">
      <header className = "App-header">
        <h1>Map</h1>
       </header>
       <div className = "Map">
         <Navbar parentControl = {this.doParentControl}/>
         <MapComponent name = {this.state.name} selected = {this.state.selected}/>
       </div>
       <div className = "clearfix" />
   </div>
   );
}
...

Navbar.js (Child)
...

constructor(props) {
    super(props);
    this.selected = [false, false, false];
    this.state = { name: 'tile' };
}

handleClick = (e) => {
    this.setState({name: e.target.value});
}

handleChangeEvent = (e) => {

     let index = e.target.value.match(/\d/); // fetch the idx
     this.setState({ selected: this.selected[index] = e.target.checked}, () => {  
        this.doParentControlFromChild()
     })

}

doParentControlFromChild = () => {
    this.props.parentControl(this.state.name, this.selected);
}

render() {
    console.info('render Navbar ->')
    return (
        <div className = "nav-bar">
            <nav className = "App-nav">
                <div className = "buttons">
                    <button name = "tile"        onClick = {this.handleClick} value = "tile">Tile</button>
                    <button name = "tile-watercolor" onClick = {this.handleClick} value = "tile-watercolor">Tile WaterColor</button>
                    <button name = "cartografia" onClick = {this.handleClick} value = "cartografia">Cartografía</button>
                    <button name = "satelite"    onClick = {this.handleClick} value = "satelite">Satélite</button>
                    <button name = "mapa"        onClick = {this.handleClick} value = "mapa">Mapa</button>
                </div>
                <div className = "clearfix"></div>
            </nav>
            <div className = "checkbox">
                <label><input type = "checkbox" name = "option1" value = "option1"  onChange = {this.handleChangeEvent} />Option 1</label>
                <label><input type = "checkbox" name = "option2" value = "option2"   onChange = {this.handleChangeEvent} />Option 2</label>
                <label><input type = "checkbox" name = "option3" value = "option3"      onChange = {this.handleChangeEvent} />Option 3</label>
            </div>
            <div className = "clearfix" />
        </div>
    );
}

Другие вопросы по теме