将行动与纯粹的反应中的状态变化联系起来

时间:2017-05-28 15:30:45

标签: javascript reactjs

学习反应所以可能有点不成熟的问题。请考虑以下代码:

class Application extends React.Component {
  render() {
    return <Container />
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isOn: false
    }
    this.handleToggle = this.handleToggle.bind(this);
  }

  handleToggle(on) {
    this.setState({
      isOn: on
    });
  }

  render() {
    return ( 
      <div>
      <p>
        {this.state.isOn ? 'on' : 'off'}
      </p>
      <MyButton handleToggle={this.handleToggle} />
        </div>
    );
  }
}


class MyButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pressed: false
    }
    this.handleButtonToggle = this.handleButtonToggle.bind(this);
  }


  handleButtonToggle() {
    const on = !this.state.pressed
    this.setState({
      pressed: on
    });
    this.props.handleToggle(on);
  }

  render() {
    return (
      <div>
        <button onClick={this.handleButtonToggle}>
          {this.state.pressed ? "pressed" : "depressed"}
        </button>
      </div>
    );
  }
}

ReactDOM.render(<Application />, document.getElementById('app'));

正如您在当前单击Container中的按钮时所看到的那样handleButtonToggle()被触发,这会更改按钮本身的状态,然后调用函数来更改父Container的状态。这是React的做法吗?当函数handleButtonToggle被触发时,容器状态被更改。理想情况下,我希望Container状态直接依赖于MyButton 状态(因为将来可能会有通过handleButtonToggle设置按钮状态的方法,我不想手动每次状态改变时都要调用this.props.handleToggle。换句话说,当状态发生变化时,有一种方法可以在按钮组件中执行类似this.props.handleToggle(this.state.pressed)的操作。

Codepen

3 个答案:

答案 0 :(得分:2)

在查看代码之后,编写Button组件的更好方法是使其成为受控组件。如果容器组件需要保持按下状态,受控按钮组件将从容器组件接收按压状态作为道具。

 <MyButton pressed={this.state.pressed} onToggle={this.handleToggle} />

Button组件的render方法应为:

render() {
    return (
      <div>
        <button onClick={this.props.onToggle}>
          {this.props.pressed ? "pressed" : "depressed"}
        </button>
      </div>
    );
  }

实际的按钮切换将在容器组件的handleToggle方法中完成:

 handleButtonToggle() {
    let { pressed } = this.state;
    pressed = !pressed;
    this.setState({
      pressed
    });
  }

答案 1 :(得分:1)

您可以将回调作为第二个参数传递给setState,也可以在组件上实现componentDidUpdate以等待状态更改。最小的变化是前者:

handleButtonToggle() {
  const on = !this.state.pressed
  this.setState({
    pressed: on
  }, () => {
    this.props.handleToggle(on);
  });
}

componentDidUpdate

componentDidUpdate(prevProps, prevState) {
  if (prevState.on !== this.state.on) {
    this.props.handleToggle(this.state.on);
  }
}

答案 2 :(得分:-1)

这是一个有效的代码:https://codepen.io/damien-monni/pen/XRwewV。 我尽可能多地保留您的代码,以便您可以专注于真正需要的更改。

您需要创建controlled component。按钮的状态将存储在容器中,并通过props传递给子MyButton组件。

/*
 * A simple React component
 */
class Application extends React.Component {
  render() {
    return <Container />
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isOn: false
    }
    this.handleToggle = this.handleToggle.bind(this);
  }

  handleToggle() {
    this.setState({
      isOn: !this.state.isOn
    });
  }

  render() {
    return ( 
      <div>
      <p>
        {this.state.isOn ? 'on' : 'off'}
      </p>
      <MyButton pressed={this.state.isOn} handleToggle={this.handleToggle} />
        </div>
    );
  }
}


class MyButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pressed: this.props.pressed
    }
    this.handleButtonToggle = this.handleButtonToggle.bind(this);
  }


  handleButtonToggle() {
    this.props.handleToggle();
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.pressed !== this.props.pressed) {
      this.setState({ pressed: nextProps.pressed });
    }
  }

  render() {
    return (
      <div>
        <button onClick={this.handleButtonToggle}>
          {this.state.pressed ? "pressed" : "depressed"}
        </button>
      </div>
    );
  }
}


/*
 * Render the above component into the div#app
 */

ReactDOM.render(<Application />, document.getElementById('app'));

您需要这样做,因为您想要在两个组件之间共享状态。这是documented here

我让你看看codepen并询问你的问题。 ;)