Я новичок в 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>
);
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


{ this.doParentControlFromChild() } выполняет вызов функции при рендеринге, что вызывает изменение состояния, что вызывает повторный рендеринг, следовательно, ваш цикл. Избавьтесь от скобок и разрешите вызывать только функцию, вызывающую setState, из действия пользователя, а не просто вызов рендеринга. Что-то вроде этого подойдет:
<div className = "clearfix" onClick = {this.doParentControlFromChild}/>
Спасибо!! Я понимаю, что обратный вызов от ребенка должен быть внутри элемента html. medium.com/@ruthmpardee/… 1 - если я помещаю внутри clearfix только рендеринг дочернего элемента и не передаю данные родительскому 2 - overide onClick и handleClick не работает
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>
);
}
спасибо Tomasz за редактирование текста