从React JS中的子组件更新道具

时间:2019-09-14 10:02:49

标签: reactjs

我刚接触React Js,对于以下情况我确实感到困惑。我的父组件中有一个名为availableShops的数组,我只是使用 setState 在子组件中对其进行了更新。我也想在子组件中保留setState方法。

父母:

import React, { Component } from 'react';
import Child from './shop-with-price';
export default class Parent extends Component {

    constructor(props) {
        super(props);
        this.state = {
        availableShops:[]
        }
    }
    render{
           return (
             <div>
                 <Child 
                    shops = {this.state.shops}
                    onChange = {this.handleInputChange}
                    avalilableShops = {this.state.avalilableShops}
                  />  
             </div>
           );
          }
}

子组件

import React, { Component } from 'react';
export default class Child extends Component {

         constructor(props) {
           super(props);
           this.state = {
            avalilableShops: this.props.avalilableShops,

           }
         }

 handleInputChange(e) {
          const target = e.target;
          const name = target.name;
          const value = target.value;


          this.setState({
              [name]: value
          });
      }

createShops(e){

          e.preventDefault();
          let shopName = this.state.shop_name;
          let phonePrice = this.state.phone_price;

          const phoneInfo = {'shop_name':shopName, 'phone_price':phonePrice};

          this.setState((preState) => ({
            avalilableShops: [...preState.avalilableShops, phoneInfo]
        }), ()=>{ console.log(this.state.avalilableShops)});
       }

render() {

        const rows = this.state.avalilableShops.map((record,index) => {

            return (
                  <tr key={index}>
                    <td>{record.shop_name}</td>
                    <td>{record.phone_price}</td>
                    <td>
                      <button 
                      type="button" 
                      className="btn btn-primary"
                      // onChange={this.createShops}
                      >
                        Delete
                      </button>
                    </td>
                  </tr>
            );
        });

           return (
             <div>
               <label>Add shops that phone already available...</label>
               <div className="row">
                 <div className="col-md-6">
                   <div className="form-group">
                     <select
                      name="shop_name"
                       className="form-control select2"
                       onChange={this.handleInputChange}
                     >
                       {this.state.shops.map((shops, index) => (
                         <option key={index} value={shops.name}>
                           {shops.name}
                         </option>
                       ))}
                       ;
                     </select>
                   </div>
                 </div>
                 <div className="col-md-4">
                   <div className="form-group">
                     <input
                       type="number"
                       name="phone_price"
                       placeholder="Price"
                       className="form-control"
                       value={this.state.phone_price}
                       onChange={this.handleInputChange}
                     />
                   </div>
                 </div>
                 <div className="col-md-2">
                 <button 
                      type="button" 
                      className="btn btn-primary"
                      onClick={this.createShops.bind(this)}
                      >
                        Add
                      </button>
                 </div>
               </div>
               <br />
               <table className="table table-striped">
                 <thead>
                   <tr>
                     <th scope="col">Shop name</th>
                     <th scope="col">Price</th>
                     <th scope="col">Remove</th>
                   </tr>
                 </thead>
                 <tbody>{rows}</tbody>
               </table>
             </div>
           );
         }
       }

我希望所有这些更改都发生在子组件中,因为在& createShop 方法中,我会使用传播运算符更新availableShops。渲染组件很好。 availableShops数组现在不会更新,但是我也想在父组件中使用它。请帮助我解决这个问题。

3 个答案:

答案 0 :(得分:1)

不要将app.config['MONG_DBNAME'] = '<DB_name>' app.config['MONGO_URI'] = 'mongodb+srv://<name>:<password>@<cluster_name>.net/<DB_name>?retryWrites=true' 存储到子组件的props

state

相反,您可以直接使用avalilableShops: this.props.avalilableShops, 来迭代并在子组件中显示数据,

props

对商店也是如此

const rows = this.props.avalilableShops.map((record,index) => {   //access data using this.props
   ...
}

由于需要在父组件中访问数据,因此在父组件中应具有一个函数,该函数将更改父组件中的状态。将该功能传递给子组件,

在父组件中创建一个函数

{this.props.shops.map((shops, index) => (  //access shops using this.props
     <option key={index} value={shops.name}>
         {shops.name}
     </option>
))}

将此功能传递给子组件

createShops = (phoneInfo) => {
   this.setState({
     avalilableShops: [...this.state.avalilableShops, phoneInfo]
   }, ()=>{ console.log(this.state.avalilableShops)});
}

现在在子组件中,您需要调用父组件中的函数以更新状态,

<Child 
     shops = {this.state.shops}
     onChange = {this.handleInputChange}
     avalilableShops = {this.state.avalilableShops}
     createShops = {this.createShops}
/>  

答案 1 :(得分:1)

我已经更新了您的代码,并使其适用于您。

我在这里为您创建了演示
https://codesandbox.io/s/smoosh-night-33yn4

父组件

constructor(props) {
    super(props);
    this.state = {
      availableShops: []
    };
    this.createShops = this.createShops.bind(this);
  }

  createShops(shop_name, phone_price) {
    this.setState(preState => ({
      availableShops: [...preState.availableShops, { shop_name, phone_price }]
    }));
  }

  render() {
    return (
      <div>
        <Child
          createShops={this.createShops}
          availableShops={this.state.availableShops}
        />
      </div>
    );
  }

子组件

import React, { Component } from "react";
export default class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      shop_name: "Shop 1",
      phone_price: ""
    };
    this.shops = [{ name: "Shop 1" }, { name: "Shop 2" }, { name: "Shop 3" }];
    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(e) {
    const { name, value } = e.target;
    this.setState({ [name]: value });
  }

  render() {
    const rows =
      this.props.availableShops &&
      this.props.availableShops.map((record, index) => {
        return (
          <tr key={index}>
            <td>{record.shop_name}</td>
            <td>{record.phone_price}</td>
            <td>
              <button
                type="button"
                className="btn btn-primary"
                // onChange={this.createShops}
              >
                Delete
              </button>
            </td>
          </tr>
        );
      });

    return (
      <div>
        <label>Add shops that phone already available...</label>
        <div className="row">
          <div className="col-md-6">
            <div className="form-group">
              <select
                name="shop_name"
                className="form-control select2"
                onChange={this.handleInputChange}
              >
                {this.shops &&
                  this.shops.map((shops, index) => (
                    <option key={index} value={shops.name}>
                      {shops.name}
                    </option>
                  ))}
                ;
              </select>
            </div>
          </div>
          <div className="col-md-4">
            <div className="form-group">
              <input
                type="number"
                name="phone_price"
                placeholder="Price"
                className="form-control"
                value={this.state.phone_price}
                onChange={this.handleInputChange}
              />
            </div>
          </div>
          <div className="col-md-2">
            <button
              type="button"
              className="btn btn-primary"
              onClick={() => {
                debugger;
                const { shop_name, phone_price } = this.state;
                this.props.createShops(shop_name, phone_price);
              }}
            >
              Add
            </button>
          </div>
        </div>
        <br />
        <table className="table table-striped">
          <thead>
            <tr>
              <th scope="col">Shop name</th>
              <th scope="col">Price</th>
              <th scope="col">Remove</th>
            </tr>
          </thead>
          <tbody>{rows}</tbody>
        </table>
      </div>
    );
  }
}

输出

enter image description here

希望这对您有用!

答案 2 :(得分:0)

我将避免在父母和孩子中都保持avialableShops的状态。相反,我只会在您的父组件中维护availableShops的状态,可以通过将功能传递给子组件来对其进行更新。子组件可以通过父状态通过道具访问可用的商店,并且应在父状态/道具更新时重新呈现。这里是一个简化的解决方案:

export default class Parent extends Component {

    constructor(props) {
        super(props);
        this.state = { availableShops:[] }
    }

    handleUpdateShops = newShop => {
      { availableShops: oldShops }  = this.state;
      this.setState({ availableShops: [...oldShops, newShop] });
    }

    render{
           return (
             <div>
                 <Child 
                    {...this.props}
                    {...this.state}
                    handleUpdateShops={this.handleUpdateShops}
                  />  
             </div>
           );
          }
       }


export default class Child extends Component {

         constructor(props) {
           super(props);
         }

     handleInputChange(e) {
       ...
      }

    createShops(e) {

          e.preventDefault();
          let shopName = this.state.shop_name;
          let phonePrice = this.state.phone_price;

          const phoneInfo = {'shop_name':shopName, 'phone_price':phonePrice};
          this.props.handleUpdateShops(phoneInfo);
    }

     render() {
      // this.props.availableShops available to map here
    }
  }