【问题标题】:How to get values from child components in React如何从 React 中的子组件获取值
【发布时间】:2016-06-18 10:48:32
【问题描述】:

所以我刚开始使用 React,但在收集子组件中输入的输入值时遇到了麻烦。基本上,我正在为我正在制作的大型表单创建不同的组件,然后在包含的组件中,我想收集我正在调用数据的对象中子项的所有输入值,然后将收集到的输入发送到 POST AJAX 请求(您可以在我制作的最后一个组件中看到一个示例)。当我在组件内部时,我可以很容易地提取值,但是从父组件中提取它们我还没有弄清楚。

提前致谢。刚刚经历了 React 的痛苦,所以关于如何更好地构建它的任何建议,我都在听!

这是我的组件:

组件一

var StepOne = React.createClass({
  getInitialState: function() {
    return {title: '', address: '', location: ''};
  },
  titleChange: function(e) {
    this.setState({title: e.target.value});
  },
  addressChange: function(e) {
   this.setState({address: e.target.value});
  },
  locationChange: function(e) {
    this.setState({location: e.target.value});
  },
  render: function() {
    return (
      <div className="stepOne">
        <ul>
          <li>
            <label>Title</label>
            <input type="text" value={this.state.title} onChange={this.titleChange} />
          </li>
          <li>
            <label>Address</label>
            <input type="text" value={this.state.address} onChange={this.addressChange} />
          </li>
          <li>
            <label>Location</label>
            <input id="location" type="text" value={this.state.location} onChange={this.locationChange} />
          </li>
        </ul>
      </div>
    );
  }, // render
}); // end of component

组件二

var StepTwo = React.createClass({
  getInitialState: function() {
    return {name: '', quantity: '', price: ''}
  },
  nameChange: function(e) {
    this.setState({name: e.target.value});
  },
  quantityChange: function(e) {
    this.setState({quantity: e.target.value});
  },
  priceChange: function(e) {
    this.setState({price: e.target.value});
  },
  render: function() {
    return (
      <div>
      <div className="name-section">
        <div className="add">
          <ul>
            <li>
              <label>Ticket Name</label>
              <input id="name" type="text" value={this.state.ticket_name} onChange={this.nameChange} />
            </li>
            <li>
              <label>Quantity Available</label>
              <input id="quantity" type="number" value={this.state.quantity} onChange={this.quantityChange} />
            </li>
            <li>
              <label>Price</label>
              <input id="price" type="number" value={this.state.price} onChange={this.priceChange} />
            </li>
          </ul>
        </div>
      </div>
      </div>
    );
  }
});

收集数据并提交ajax请求的最终组件

EventCreation = React.createClass({
 getInitialState: function(){
  return {}
},
submit: function (e){
  var self

  e.preventDefault()
  self = this

  var data = {
    // I want to be able to collect the values into this object then send it in the ajax request. I thought this sort of thing would work below:
    title: this.state.title,
  }

  // Submit form via jQuery/AJAX
  $.ajax({
    type: 'POST',
    url: '/some/url',
    data: data
  })
  .done(function(data) {
    self.clearForm()
  })
  .fail(function(jqXhr) {
    console.log('failed to register');
  });
},
render: function() {
    return(
      <form>
        <StepOne />
        <StepTwo />
        // submit button here
      </form>
    );
  }
});

【问题讨论】:

    标签: reactjs ajax


    【解决方案1】:

    在子组件中定义返回所需数据的方法,然后在渲染子组件时在父组件中定义方法,以便稍后在要检索所需数据时调用这些方法孩子们。

    StepOne = React.createClass({
        getData: function() {
            return this.state;
        }
    });
    
    StepTwo = React.createClass({
        getData: function() {
            return this.state;
        }
    });
    
    EventCreation = React.createClass({
        submit: function() {
            var data = Object.assign(
                {},
                this._stepOne.getData(),
                this._stepTwo.getData()
            );
    
            // ... do AJAX
        },
    
        render: function() {
            return (
                <StepOne ref={(ref) => this._stepOne = ref} />
                <StepTwo ref={(ref) => this._stepTwo = ref} />
            );
        }
    });
    

    【讨论】:

    • 这有很多支持,看起来更简单/比 value={} 和 onChange={} 方法更少的代码.. 但我真的不明白发生了什么,为什么会这样,或者为什么它在反应中是可以接受的。
    【解决方案2】:

    一般来说,您会希望将一个函数作为道具从父级传递给子级。当孩子的数据发生变化时,他们会调用该函数作为回调。

    这有一个很大的优势,就是让您的父组件跟踪应用程序中的所有状态,并将状态切片作为道具传递给它的子组件,而不是让每个组件跟踪自己的内部状态。 (That's the React approach to data flow.)

    您的组件可能如下所示:

    var StepOne = React.createClass({
      handleOnChange: function(e){
         this.props.handleChange(e.target.name, e.target.value);
      },      
      render: function() {
        return (
          <div className="stepOne">
            <ul>
              <li>
                <label>Title</label>
                <input type="text" name="title" value={this.props.title} onChange={this.handleChange} />
              </li>
              ...
            </ul>
          </div>
        );
      }, // render
    }); // end of component
    
    EventCreation = React.createClass({
     getInitialState: function(){
      return {}
    },
    handleChange: function(name, value){
        var tmp = {};
        tmp[name] = value;
        this.setState(tmp);
    },
    submit: function (e){
      var self
    
      e.preventDefault()
      self = this
    
      var data = {
        // I want to be able to collect the values into this object then send it in the ajax request. I thought this sort of thing would work below:
        title: this.state.title,
      }
    
      // Submit form via jQuery/AJAX
      $.ajax({
        type: 'POST',
        url: '/some/url',
        data: data
      })
      .done(function(data) {
        self.clearForm()
      })
      .fail(function(jqXhr) {
        console.log('failed to register');
      });
    },
    render: function() {
        return(
          <form>
            <StepOne handleChange={this.handleChange.bind(this)} title={this.state.title} .../>
            <StepTwo handleChange={this.handleChange.bind(this)} ... />
            // submit button here
          </form>
        );
      }
    });
    

    【讨论】:

    • 你打败了我,但我喜欢你的想法;)
    • 嗨 ajm,感谢您的帮助。这绝对是我要实现它的方式。我更改了stepOne组件中的handleOnChange函数,认为是拼写错误。在我的反应控制台中,我可以看到在我输入时呈现的状态,但是没有与输入的值关联的键。这就是title={this.state.title} 在最终组件的 StepOne 渲染中的意思吗?
    • title={this.state.title} 会将titleEventCreation 的状态传递到StepOne 作为道具。然后,您可以通过this.props.titleStepOne 中访问它(在您的情况下,看起来您正在设置输入的值)。如果您尝试获取输入内容的密钥,则需要通过StepOne 级别的函数传递该密钥,该函数调用EventCreationhandleChange 函数并将其作为参数传递。
    【解决方案3】:

    首先,您需要设置一些references。它将允许您轻松访问一些 DOM 元素。 例如:

    <input id="name" type="text" value={this.state.ticket_name} onChange={this.nameChange} ref="stepOneName"/>
    

    然后,在您的 submit 方法中,您可以像这样将其取回:

    var data = {
    name: this.refs.stepOneName.value
    }
    

    编辑 1: 您还必须将ref 添加到您的组件中:

    渲染:函数(){ 返回( // 这里提交按钮 ); } 然后,访问您的元素:

    var data = {
        name: this.refs.steOneRef.refs.stepOneName.value
        }
    

    I JSFiddled your codeant 对我来说似乎没问题。

    【讨论】:

    • 我之前尝试过使用它,但是当我尝试控制数据的值时,我总是收到value is not defined 错误。知道为什么会发生这种情况吗?
    【解决方案4】:

    这是一个稍微松散耦合的解决方案。这取决于您为每个元素设置一个id。基本上你所做的是调用父组件onChange 函数来获取和设置数据。

    var StepOne = React.createClass({
      getInitialState: function() {
        return {title: '', address: '', location: ''};
      },
      _onChange(e) {
        // set your state if needed
    
        // call the parent function
        this.props.onChange(
            e.target.id,
            e.target.value
        )
      },
      render: function() {
        return (
          <div className="stepOne">
            <ul>
              <li>
                <label>Title</label>
                <input id="title" type="text" value={this.state.title} onChange={this._onChange.bind(this)} />
              </li>
              <li>
                <label>Address</label>
                <input id="address" type="text" value={this.state.address} onChange={this._onChange.bind(this)} />
              </li>
              <li>
                <label>Location</label>
                <input id="location" type="text" value={this.state.location} onChange={this._onChange.bind(this)} />
              </li>
            </ul>
          </div>
        );
      }, // render
    }); // end of component
    
    var StepTwo = React.createClass({
      getInitialState: function() {
        return {name: '', quantity: '', price: ''}
      },
      _onChange(e) {
        // set your state if needed
    
        // call the parent function
        this.props.onChange(
            e.target.id,
            e.target.value
        )
      },
      render: function() {
        return (
          <div>
          <div className="name-section">
            <div className="add">
              <ul>
                <li>
                  <label>Ticket Name</label>
                  <input id="name" type="text" value={this.state.ticket_name} onChange={this._onChange.bind(this)} />
                </li>
                <li>
                  <label>Quantity Available</label>
                  <input id="quantity" type="number" value={this.state.quantity} onChange={this._onChange.bind(this)} />
                </li>
                <li>
                  <label>Price</label>
                  <input id="price" type="number" value={this.state.price} onChange={this._onChange.bind(this)} />
                </li>
              </ul>
            </div>
          </div>
          </div>
        );
      }
    
      EventCreation = React.createClass({
        getInitialState: function(){
          return {}
        },
        _onChange(id, value) {
          this.formData[id] = value;
        },
        submit: function (e){
          var self
    
          e.preventDefault()
          self = this
    
          // Submit form via jQuery/AJAX
          $.ajax({
            type: 'POST',
            url: '/some/url',
            data: this.formData
          })
          .done(function(data) {
            self.clearForm()
          })
          .fail(function(jqXhr) {
            console.log('failed to register');
          });
      },
      render: function() {
          return(
            <form>
              <StepOne onChange={this.onChange.bind(this)}/>
              <StepTwo onChange={this.onChange.bind(this)}/>
              // submit button here
            </form>
          );
        }
    });
    

    【讨论】:

      【解决方案5】:

      我使用这种方法从子组件中收集表单字段的值:

      父组件:

      import { useEffect, useState } from "react";
      import DetailFields from "./DetailFields";
      
      export default function ParentComponent(props) {
        //Set initial Values
        const [model, setModel] = useState(props.initModel);
      
        useEffect(() => {
          setModel(props.initModel);
        }, [props.initModel]);
      
        //  call API
        const handleSubmit = (event) => {
          //...Here you have model values and you can send it to api
          callApi(model);
        };
      
        // Set Values from the input to the model when the values changed
        const handleChange = (event) => {
          // get the value of the field
          const value = event?.target?.value;
          //set it in the model
          setModel({
            ...model,
            [event.target.name]: value,
          });
        };
      
        return (
          <form>
            <div>
              <DetailFields
                model={model}
                // pass the function to child component
                handleChange={handleChange}
              />
      
              <input type="submit" value="Submit" onClick={handleSubmit} />
            </div>
          </form>
        );
      }
      

      子组件:

      import React from "react";
      
      export default function DetailFields(props){
        return (
      
           <div className="stepOne">
                <ul>
                     <li>
                          <label>First Field</label>
                          <input id="FirstField" type="text" value={props.model.FirstField || ""} onChange={props.handleChange} />
                     </li>
                     <li>
                          <label>Second Field</label>
                          <input id="SecondField" type="text" value={props.model.SecondField || ""} onChange={props.handleChange} />
                     </li>
                </ul>
           </div>
      
        );
      };
      

      【讨论】:

        猜你喜欢
        • 2021-11-10
        • 1970-01-01
        • 2020-03-25
        • 2019-05-13
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 2021-10-26
        • 1970-01-01
        相关资源
        最近更新 更多