反应无限循环

时间:2018-03-18 13:11:37

标签: javascript reactjs react-redux

我是React的新手,对不起我的英语。

当我将数据从Child传递到父组件并单击另一个按钮时,它不会呈现。

正如您在我的注释中所看到的,setState创建了一个无限循环,停止了更新值的选项。

我尝试了不同的方法来解决在this.name = ''this.selected = []等内部构造变量中创建问题,并将回调设置为this.name = namethis.selected = selected但不渲染当我点击其他选项时。

我尝试使用componentDidMount()和其他生命周期方法,但我不知道如何解决它。

App.js(父组件)

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

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

render() {
   console.log('-> 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});
}

handleChange = (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.log('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.handleChange} />Option 1</label>
                <label><input type="checkbox" name="option2" value="option2"   onChange={this.handleChange} />Option 2</label>
                <label><input type="checkbox" name="option3" value="option3"      onChange={this.handleChange} />Option 3</label>
            </div>
            <div className="clearfix" />
            { this.doParentControlFromChild() }
        </div>
    );
}

2 个答案:

答案 0 :(得分:1)

{ this.doParentControlFromChild() }正在对渲染进行函数调用,这会导致状态更改,从而导致重新渲染,从而导致循环。摆脱parens并且只允许从用户操作调用调用setState的函数,而不仅仅是渲染调用。这样的事情会做:

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

答案 1 :(得分:1)

setState()render()函数重新渲染 因此,setState()部署在父组件中的doParentControl会导致组件重新呈现,而在您的子组件中,return( ... { this.doParentControlFromChild()} ... )只会伴随元素呈现。这会导致您的父组件doParentControl再次被调用,所以这里我们有无限循环 就像之前的回答所说的那样,只有在需要发生时才需要调用doParentControlFromChild

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

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

render() {
   console.log('-> 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});
}

handleChange = (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.log('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.handleChange} />Option 1</label>
                <label><input type="checkbox" name="option2" value="option2"   onChange={this.handleChange} />Option 2</label>
                <label><input type="checkbox" name="option3" value="option3"      onChange={this.handleChange} />Option 3</label>
            </div>
            <div className="clearfix" />
        </div>
    );
}