【问题标题】:React - Can A Child Component Send Value Back To Parent FormReact - 子组件可以将值发送回父表单吗
【发布时间】:2017-05-27 21:55:54
【问题描述】:

InputFieldButton 是自定义组件,它们进入表单以创建表单。我的问题是如何将数据发送回表单,以便在单击按钮时,我可以使用数据(用户名和密码)在表单上触发 ajax:

export default auth.authApi(
  class SignUpViaEmail extends Component{

    constructor(props){
      super(props);
      this.state = {
        email : "",
        password : ""
      };
      this.storeEmail = this.storeEmail.bind( this );
      this.storePassword = this.storePassword.bind( this );
    }

    storeEmail(e){
      this.setState({ email : e.target.value });
    }

    storePassword(e){
      this.setState({ password : e.target.value });
    }

    handleSignUp(){
      this.props.handleSignUp(this.state);
    }

    render(){
      return(
        <div className="pageContainer">

          <form action="" method="post">
            <InputField labelClass = "label"
                        labelText = "Username"
                        inputId = "signUp_username"
                        inputType = "email"
                        inputPlaceholder = "registered email"
                        inputClass = "input" />
            <Button btnClass = "btnClass"
                    btnLabel = "Submit"
                    onClickEvent = { handleSignUp } />
          </form>
        </div>
      );
    }

  }
);

或者不推荐并且我不应该在表单中创建自定义子组件?

子组件 => InputField

import React,
       { Component } from "react";

export class InputField extends Component{

  constructor( props ){
    super( props );
    this.state = {
      value : ""
    };
    this.onUserInput = this.onUserInput.bind( this );
  }

  onUserInput( e ){
    this.setState({ value : e.target.value });
    this.props.storeInParentState({[ this.props.inputType ] : e.target.value });
  }

  render(){
    return  <div className = "">
              <label htmlFor = {this.props.inputId}
                     className = {this.props.labelClass}>
                {this.props.labelText}
              </label>
              <input id = {this.props.inputId}
                     type = {this.props.inputType}
                     onChange = {this.onUserInput} />
              <span className = {this.props.validationClass}>
                { this.props.validationNotice }
              </span>
            </div>;
  }
}

错误:我在父 storeEmail 函数上收到错误 e.target is undefined

【问题讨论】:

  • 您可以将keyup 事件处理程序传递给输入,以便父组件状态始终保持最新。然后,每当调用 handleSignup 时,表单组件就已经拥有它需要的一切。
  • @rufio86 是对的,你需要先更新你的父组件状态。并且你需要绑定handleSignUp回调,然后你就会得到你的状态。
  • 向@rufio86 和 hawk 道歉,请详细说明

标签: javascript forms reactjs input components


【解决方案1】:

React 的单向数据绑定模型意味着子组件不能将值发送回父组件除非明确允许这样做。这样做的 React 方法是将回调传递给子组件(参见 Facebook's "Forms" guide)。

class Parent extends Component {
  constructor() {
    this.state = {
      value: ''
    };
  }
  
  //...
  
  handleChangeValue = event => this.setState({value: event.target.value});
  
  //...
  
  render() {
    return (
      <Child
        value={this.state.value}
        onChangeValue={this.handleChangeValue}
      />
    );
  }
}

class Child extends Component {
  //...
  
  render() {
    return (
      <input
        type="text"
        value={this.props.value}
        onChange={this.props.onChangeValue}
      />
    );
  }
}

注意父组件处理状态,子组件只处理显示Facebook's "Lifting State Up" guide 是学习如何做到这一点的好资源。

这样,所有数据都存在于父组件中(处于状态中),而子组件只提供了一种更新数据的方法(回调作为 props 向下传递)。现在您的问题解决了:您的父组件可以访问它需要的所有数据(因为数据存储在 state 中),但您的子组件负责将数据绑定到它们自己的单个元素,例如 &lt;input&gt; 标签.


附录

回应此评论:

如果我们渲染一个子组件的列表呢?在提升状态技术中使用这种单一事实来源将让父级控制所有子级输入的所有状态,对吗?那么我们如何从父组件访问子组件中输入的每个值(呈现为列表)?

对于这种情况,您可以为列表中的每个元素映射一个子组件。例如:

class Parent extends Component {
  //...
  handleChangeListValue = index => event => {
    this.setState({
      list: this.state.list
        .map((element, i) => i === index ? event.target.value : element)
    });
  }
  //...
  render() {
    return this.state.list.map((element, i) => (
      <Child
        value={element}
        onChangeValue={this.handleChangeListValue(i)}
      />
    ));

P.S. 免责声明:以上代码示例仅用于说明相关概念(Lifting State Up),并反映了回答时 React 代码的状态。有关代码的其他问题,例如不可变与可变数组更新、静态与动态生成函数、有状态与纯组件以及基于类与基于钩子的有状态组件,最好作为一个单独的问题一起提出。

【讨论】:

  • 伊恩回答得很好。但是我很好奇如果我们渲染一个子组件的列表呢?在提升状态技术中使用这种单一事实来源将让父级控制所有子级输入的所有状态,对吗?那么我们如何从父组件访问子组件中输入的每个值(呈现为列表)?
  • @Mark 我已包含一个附录来解决您的问题。
【解决方案2】:

父.js

import React, { Component } from 'react';
import Child from './child'
class Parent extends Component {
  state = {
    value: ''
  }
  onChangeValueHandler = (val) => {
    this.setState({ value: val.target.value })
  }
  render() {
    const { value } = this.state;
    return (
      <div>
        <p> the value is : {value} </p>
        <Child value={value} onChangeValue={this.onChangeValueHandler} />
      </div>
    );
  }
}

export default Parent;

Child.js

  import React, { Component } from 'react';
  class Child extends Component {
  render() {
  const { value , onChangeValue } = this.props;
  return (
    <div>
      <input type="text"  value={value} onChange={onChangeValue}/> 
    </div>
  );
}
}
  export default Child;

你可以在https://codesandbox.io/s/two-way-binding-qq1o1?from-embed上看到一个活生生的例子

【讨论】:

    【解决方案3】:

    您可以在 InputField 中添加“参考名称”,以便从中调用某些函数,例如:

    <InputField 
       ref="userInput"
       labelClass = "label"
       labelText = "Username"
       inputId = "signUp_username"
       inputType = "email"
       inputPlaceholder = "registered email"
       inputClass = "input" />
    

    所以你可以使用 refs 访问它:

    this.refs.userInput.getUsernamePassword();
    

    getUsernamePassword 函数在 InputField 组件中的位置,通过返回,您可以设置状态并调用您的 props.handleSignUp

    【讨论】:

    • 虽然这工作,但通常不建议将引用附加到组件,更不用说从子组件获取值了。通过传递回调可以更直接地解决此问题,这是执行此操作的规范方法。 (见Facebook's React guide
    • 确实,在他的情况下,ref 方法是最简单的方法,但是是的,回调也是一个不错的选择。
    • 作为字符串的引用被视为遗留代码,可能会被删除:facebook.github.io/react/docs/refs-and-the-dom.html
    猜你喜欢
    • 2020-09-28
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 2021-11-29
    • 2020-07-25
    • 2015-05-14
    相关资源
    最近更新 更多