Search code examples
reactjsformsreact-reduxreact-state-management

How to design State for Multiple objects using react-redux?


I need to create multiple medicine objects here. I just want to change state into array of objects. How to do that effectively? Also, want to implement controlled component for multiple medicine objects form.

Form Design

Here's my component for a single medicine object:

export class MedicineForm extends Component {
    state = {
        medicine_name: "",
        details: ""
    }

    static propTypes = {
        postMedicine: PropTypes.func.isRequired
    }

    onChange = e => {
        this.setState({
          [e.target.name]: e.target.value
        })
    }

    onSubmit = e => {
        e.preventDefault()
        const { medicine_name, details } = this.state
        const medicine = { medicine_name, details }
        this.props.postMedicine(medicine)
        // Following code works as desired.  Need to change state in this JSON Array of objects.

        // this.props.postMedicine([
        //  {
        //      "id": 14,
        //      "medicine_name": "many5",
        //      "details": "sdknas"
        //  },
        //  {
        //      "id": 15,
        //      "medicine_name": "many6",
        //      "details": "sdknas"
        //  }
        // ])
    }

    render() {
        const { medicine_name, details } = this.state

        return (
          <Fragment>
            <h1>Add Medicine</h1>
            <form className="card card-body" onSubmit={this.onSubmit}>
              <div className="form-row">
                <div className="form-group col-md-3">
                  <label htmlFor="medicine_name">Medicine Name</label>
                  <input type="text" className="form-control" name="medicine_name" id="medicine_name" placeholder="Medicine Name" value={medicine_name} onChange={this.onChange} />
                </div>
                <div className="form-group col-md-3">
                  <label htmlFor="details">Details</label>
                  <input type="text" className="form-control" name="details" id="details" placeholder="Details" value={details} onChange={this.onChange} />
                </div>
                <div className="form-group mx-auto mt-3">
                  <button type="submit" className="btn btn-primary btn-lg">
                    Submit
                  </button>
                </div>
              </div>
            </form>
          </Fragment>
        )
    }
}

In actions, I have added following postMedicine method:

export const postMedicine = (medicine) => dispatch => {
    axios.post('./api/medicine/', medicine)
        .then(res => {
            dispatch({
                type: POST_MEDICINE,
                payload: res.data
            })
        })
        .catch(err => console.log(err))
}

Solution

  • //this is one row, add multiple rows as needed        
    state = {
        medicines: [{medicine_name: "",
                details: ""
        }]
        }
        //other code
    
        onChange = (e, i) => {
            const newMedicines = this.state.medicines;
            newMedicines[i] = {[e.target.name]: e.target.value, ...newMedicines[i]}
            this.setState({medicines: newMedicines})
        }
    
        onSubmit = e => {
            e.preventDefault()
            const { medicine_name, details } = this.state
            const medicine = { medicine_name, details }
            this.props.postMedicine(medicine)
            // Following code works as desired.  Need to change state in this JSON Array of objects.
    
            // this.props.postMedicine(this.state.medicines)
        }
    
    
        <form className="card card-body" onSubmit={this.onSubmit}>
                      {this.state.medicines.map((m, i) => (<div className="form-row">
                        <div className="form-group col-md-3">
                          <label htmlFor="medicine_name">Medicine Name</label>
                          <input type="text" className="form-control" name="medicine_name" id="medicine_name" placeholder="Medicine Name" value={m.medicine_name} onChange={(e) => this.onChange(e, i)} />
                        </div>
                        <div className="form-group col-md-3">
                          <label htmlFor="details">Details</label>
                          <input type="text" className="form-control" name="details" id="details" placeholder="Details" value={m.details} onChange={(e) => this.onChange(e, i)} />
                        </div>
                        <div className="form-group mx-auto mt-3">
                          <button type="submit" className="btn btn-primary btn-lg">
                            Submit
                          </button>
                        </div>
                      </div>))}
                    </form>