Nathan Barel
Nathan Barel

Reputation: 388

Updating redux state by a local state of checkbox items

there are similiar questions in stackoverflow but I I did not find what I was looking for. I have a donorDonationForm which is a class componenet that connected to the redux state. The porpuse of that componenet is to collect inormation about a person that want to donate electronics items. At this point, I want to save those items in an array (maybe with an object in the future). my redux state save the donor info and the reducer looks like this:

import {CHANGE_INPUT_FIELD} from '../utils/constants';

const initialStateInputs = {
    // update the state
    donorFields: {
        name: '',
        phone: '',
        area: '',
        yeshuv: '',
        address: ''
        // dateOfOffer: ''
    },
    donationFields: {
        // donorID: '',
        // vulonteerID: '',
        type: [],
        quantity: 1,
        status: 'NOT_HANDLED',
        comments: ''
        // lastDateHandled: ''
    }
    // }, items: [ //need to add quantity
    //         {id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
    //         {id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
    //         {id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
    //     ]   
}



export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
    switch(action.type) { 
        case CHANGE_INPUT_FIELD: 
            return Object.assign( {}, state, 
                {
                    donorFields :  {...state.donorFields,...action.payload},
                    donationFields:  {...state.donationFields,...action.payload},
                    // items :  {...state.items,...action.payload},
                    // isChecked:  action.payload
                }) 
        default:
            return state;
    }
}

As you can see the items is commented by now, and I am managing the state of the item in a local state, and that how the comp looks like:

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { setInputField } from '../actions/formAction';
import CheckBox from '../components/CheckBox/CheckBox';
import FormInput from '../components/FormInput/FormInput';
import {selectAreasOptions_2} from '../utils/constants';
import "./form.css";

const mapStateToProps = (state) => {
    return {
        donorFields: state.donorDonationInputsReducer.donorFields,
        donationFields: state.donorDonationInputsReducer.donationFields
    }
}

const mapDispatchToProps = dispatch => {
    return {
        onInputChange: event =>  {
            const {name, value} = event.target;
            dispatch(setInputField( { [name]:value} ) )
        }
    } 
}


class donorDonationForm extends Component {
    constructor() {
        super();
        this.state = {
            items: [ 
                {id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
                {id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
                {id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
            ]
            ,
            type: []
          }
    }

    handleCheckChieldElement = (event) => {
        let {items, type} = this.state;
        let arr = [];
        items.forEach(item => {
           if (item.name === event.target.value) {
               item.isChecked = event.target.checked;
            //    console.log(`item.name  :${item.name }`);
            //    console.log(`event.target.value :${event.target.value}`);
            //    console.log(`event.target.checked :${event.target.checked}`);
           }      
        })
        items.map(item => item.isChecked ? arr.push(item.name) : null)
        this.setState({items: [...items], type: [...arr]});
        
    }

    onButtonSubmit = (event) => {
        console.log(this.props.donorFields);
        event.preventDefault();
        fetch('http://localhost:8000/api/donor', {
            method: 'post', 
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ 
                ...this.props.donorFields
            })
        })
        .then(response => response.json())
        .then(resp => console.log(resp))
        .catch( err => console.log(err) )       
    }

    // componentDidUpdate(prevProps, prevState) {
    //  const {items, type} = this.state;
    //  // const type = [];
    //  if (prevState.items !== items) {
    //      console.log('items state has changed');
    //      items.map (item => item.isChecked ? 
    //          this.setState({type: [...type,item.name]}) : null)
    //          // if (item.isChecked) { type.push(item.name) } ;
            
    //      console.log(type);
    //  }
    //   }

    render() {
        console.log(this.state.items);
        console.log(this.state.type);
        const { onInputChange } = this.props;
        return (
            <div>
                <h1 className="pt4"> פרטי תורם</h1>
                <form className=" black-80 pt2" >
                    <section className=" grid-container">
                        <FormInput 
                            id="name"
                            name="name"
                            type="text"
                            onInputChange={onInputChange}
                            label="שם "
                            required
                        />
                        <FormInput 
                            id="phone"
                            name="phone"
                            type="tel"
                            onInputChange={onInputChange}
                            label="מספר טלפון "
                            required
                        />
                        <FormInput 
                            id="address"
                            name="address"
                            type="text"
                            onInputChange={onInputChange}
                            label="כתובת "
                            required
                        />
                        <FormInput 
                            id="yeshuv"
                            name="yeshuv"
                            type="text"
                            onInputChange={onInputChange}
                            label="עיר "
                            required
                        />  
                        <FormInput 
                            id="comments"
                            name="comments"
                            onInputChange={onInputChange}
                            label="הערות "
                            required
                        />
                        <FormInput 
                            id="area"
                            name="area"
                            onInputChange={onInputChange}
                            label="איזור "
                            select={selectAreasOptions_2}
                        />
                        {/* type */}
                        <div className="measure-narrow">
                            <label htmlFor="type" className="f5 b db mb2">מעוניין לתרום
                                <span className="normal black-60"> *</span>
                            </label>
                            {
                                this.state.items.map( (item, i) => {
                                    return (
                                        <CheckBox 
                                            key={i}
                                            onChange={this.handleCheckChieldElement}
                                            checked={ item.isChecked } 
                                            value= {item.name}
                                            label = {item.label}
                                        />
                                    );
                                })
                            }
                        </div>
                    </section>
                    <input type="submit" value="שלח" 
                           className="b bg-light-blue pa2 hover pointer" 
                           onClick={this.onButtonSubmit}
                    />
                </form> 
            </div>
        );
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(donorDonationForm);

My main goal is that the type array - the final donation, will update the redux state before submitting this form. I tried with componentDidUpdate but didn't make it. What is the best way for tracking the checked items, updating the array and then update the type array which is the final donation in the redux state? should I do that in the onButtonSubmit method - before sending the data to the server (and thats way saving the looping over the items array for searching the checked elements) ?

Upvotes: 1

Views: 509

Answers (1)

Rashed Rahat
Rashed Rahat

Reputation: 2485

Better approach would be do inside onButtonSubmit Let me briefly explain the tasks:

  1. inputChangeHandler to update this.state.items
  2. Go with the final this.state.items value Array of items inside onButtonSubmit
  3. After getting API response update the application level Redux state with Array of items.

Note: Dispatch the action. Reducer will update the Redux state. Following code will do this:

// Action
export const setItems = (data) => (dispatch) => {
    dispatch({type: 'SET_ITEMS', payload: data})
}

// mapDispatchToProps
const mapDispatchToProps = (dispatch) =>
    bindActionCreators(
        {
            setItems,
            ...others
        },
        dispatch
    )

// onSubmitButton
    onButtonSubmit = (event) => {
        console.log(this.props.donorFields);
        event.preventDefault();
        fetch('http://localhost:8000/api/donor', {
            method: 'post', 
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ 
                ...this.props.donorFields
            })
        })
        .then(response => this.props.setItems(response.json())) // will update the state.
        .then(resp => console.log(resp))
        .catch( err => console.log(err) )       
    }

// Reducer
export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
    switch(action.type) { 
        case CHANGE_INPUT_FIELD: 
            return Object.assign( {}, state, 
                {
                    donorFields :  {...state.donorFields,...action.payload},
                    donationFields:  {...state.donationFields,...action.payload},
                    // items :  {...state.items,...action.payload},
                    // isChecked:  action.payload
                })
        case SET_ITEMS:
            return {
                ...state,
                items: action.payload
            }
        default:
            return state;
    }
}

That's it.

Happy Coding :)

Upvotes: 1

Related Questions