【问题标题】:React: Set the state of a parent based on child's state?React:根据孩子的状态设置父母的状态?
【发布时间】:2019-10-20 12:02:49
【问题描述】:

第一次使用 React。
总之,我需要让子组件更新父组件的状态,尽管我已成功将回调函数传递给子组件,但它的行为并不符合我的预期。 我有一个组件 App,它呈现一个子组件 LoginOverlay。

组件App编写如下:

export default class App extends React.Component{
  constructor(props) {
    super(props);

    this.handleLogin = this.handleLogin.bind(this);

    this.state = {
      userID:'',
      loginState:'waiting',
      loginError:'',
    };
  }

  handleLogin(un, pw){
    //just try setting a state as if the API call came back with an error code
    this.setState({
      loginError:'Wrong Password',
    })
  }

  render() {
      return (
      <div className="App">
        {/*login overlay*/}
        <LoginOverlay loginError={this.state.loginError} loginState={this.state.loginState} parentCallback={this.handleLogin}/>
        UserID:{this.state.userID}
      </div>
    );
  }
}

子组件的写法如下:

export default class LoginOverlay extends React.Component{
  constructor(props){
    super(props);
    this.userNameChange=this.userNameChange.bind(this);
    this.passwordChange=this.passwordChange.bind(this);
    this.submitHandler=this.submitHandler.bind(this);

    this.state = {
      username:'',
      password:'',
      loginState:this.props.loginState,
      loginError:this.props.loginError,
    };
  }

  userNameChange(event) {
    this.setState({
      username: event.target.value
    });
  }

  passwordChange(event) {
    this.setState({
      password: event.target.value
    })
  }

  submitHandler(event) {
    event.preventDefault();
    if (this.state.username!=='' && this.state.password !=='') {
      this.setState({
        loginState:'loading',
        loginError:'',
      })
      this.props.parentCallback(this.state.username, this.state.password);
    }
    else {
      this.setState({
        loginError:'Fill out the form, please!'
      })
    }
  }

  render() {
      let bottompane = null;
      switch(this.state.loginState) {
        case 'waiting':
          bottompane =  <div className="login-ButtonContainer">
                          <input
                            type="submit"
                            value="Log In"
                            className="login-button"
                          />
                        </div>
          break;
        case 'loading':
          bottompane =  <div className="login-ButtonContainer">
                          {/*copypasted from loading.io*/}
                          <div className="lds-spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
                        </div>
          break;
        default:
          break;
      }

      let errorText = null;
      switch(this.state.loginError) {
        case '':
        break;
        default:
          errorText=<div className="login-errortext">{this.state.loginError}</div>
        break;
      }

      return(
      <div className="loginOverlay">
        <form onSubmit={this.submitHandler} className="login-box">
          <label>
            Username:
          </label>
          <input
            className="login-field"
            type="text"
            onChange={this.userNameChange}
          />
          <br/>
          <label>
            Password:
          </label>
          <input
            className="login-field"
            type="password"
            onChange={this.passwordChange}
          />
          <br/>
            {bottompane}
            {errorText}
        </form>
      </div>
    );
  }
}

但是,在我点击提交按钮并执行 handeLogin 后,loginError 状态没有更新(我使用 console.log(this.state.loginError) 进行检查)。我想知道是不是我的方法不对?还是我的语法?

【问题讨论】:

    标签: reactjs parent-child


    【解决方案1】:

    您不想像这样将道具镜像/复制到状态:

    // This is bad news:
    this.state = {
      loginState: this.props.loginState,
      loginError: this.props.loginError,
    };
    

    相反,只需在您需要知道该值是什么的任何地方引用this.props.loginState。这就是所谓的“托管组件”——父组件通过 props 管理状态。

    【讨论】:

    • 很高兴知道,我会做出这些改变。但是,我仍然无法从回调中使用 this.setState?
    • @BoThompson 您可以在回调中使用setState,但由于您在thisLoginOverlay 的实例时引用this.state.loginError,因此您永远不会将更改作为道具传递下来。您复制到 state 中的 props 仍然反映组件初始化时的 props(prop 更改不会卸载和重新安装基于类的组件)。
    • 啊,所以我的方法有缺陷。我最初将这两个组件设置为有状态是因为我计划让 App 组件处理所有 API 调用,并且让子组件只获取数据。我让孩子有状态,以便在将数据发送给父母后,它可以快速显示加载图标。我是否只需要将该状态信息仅保留在父级中?在添加了很多这些表单之后,这不会让父级臃肿不堪吗?
    • @BoThompson 我认为您不必担心道具传播的速度。至于架构挑战,如果不知道更多关于你在做什么,很难说,但你可能更喜欢一种方法,使用本地钩子验证和提交表单,并且只将通用状态传达给应用程序级别(即,如果你需要在提交表单时阻止整个应用程序)。
    • 这让我深思。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 2018-03-19
    • 2023-01-10
    • 2017-01-17
    • 1970-01-01
    • 2018-02-08
    相关资源
    最近更新 更多