如何从 React 中的子组件获取值

IT技术 reactjs ajax
2021-04-21 19:00:37

所以我刚刚开始使用 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>
    );
  }
});
5个回答

在子组件中定义返回您想要的数据的方法,然后在渲染子组件时在父组件中定义方法,定义 refs 以便稍后当您想要检索您需要的数据时,您可以在子组件上调用这些方法。

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} />
        );
    }
});

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

这有一个很大的优势,它可以让您的父组件跟踪应用程序中的所有状态,并将状态切片作为props传递给它的子组件,而不是让每个组件跟踪自己的内部状态。这是数据流的 React 方法。)

您的组件可能如下所示:

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>
    );
  }
});
title={this.state.title}将通过titleEventCreation的状态下,以StepOne作为道具。那么你可以访问它StepOne通过this.props.title(在你的情况下,它看起来像你设置输入的值)。如果您试图获取输入内容的密钥,您需要通过StepOne调用EventCreationhandleChange函数并将其作为参数传递级别函数传递它。
2021-05-26 19:00:37
你打败了我,但我喜欢你的想法;)
2021-05-31 19:00:37
嗨 ajm,感谢您的帮助。这绝对是我要实施它的方式。我改了stepOne组件中的handleOnChange函数,认为是拼写错误。在我的 React 控制台中,我可以看到在输入时呈现的状态,但是没有与输入的值相关联的键。title={this.state.title}是在最终组件的 StepOne 渲染中要做的事情吗?
2021-06-09 19:00:37

首先,您需要设置一些引用它将允许您轻松访问某些 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必须在组件中添加一个

render: function() { return( // 这里提交按钮); 然后,访问您的元素:

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

我 JSFiddled 你的代码蚂蚁对我来说似乎没问题。

我之前尝试过使用它,但是当我尝试控制数据的值时,我总是收到value is not defined错误消息。知道为什么会发生这种情况吗?
2021-05-23 19:00:37

这是一个稍微松散耦合的解决方案。这取决于您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>
      );
    }
});

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

父组件:

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>

  );
};