reactjsreact-reduxreact-statereact-state-managementreact-lifecycle

React - Unable to set state from the response on initial render


This is the response from redux store :

{
  "newsletter": true,
  "orderConfirmation": true,
  "shippingInformation": true,
  "orderEnquiryConfirmation": true,
}

This is the jsx file, where am trying to set state. The idea is setting the state from the response and add an onChange handle to each checkboxes.

But currently am receiving a correct response but I tried to set state in didUpdate, DidMount but no luck. I want to know the correct place to set state on initial render of the component.

import React from 'react';
import Component from '../../assets/js/app/component.jsx';
import { connect } from 'react-redux';
import * as actionCreators from '../../assets/js/app/some/actions';
import { bindActionCreators } from 'redux';
import Checkbox from '../checkbox/checkbox.jsx';

const mapStateToProps = (state, ownProps) => {
    return {
        ...state.emailSubscriptions
    }
}

const mapDispatchToProps = dispatch => {
    return {
        actions: bindActionCreators(actionCreators, dispatch)
    }
}

@connect(mapStateToProps, mapDispatchToProps)

class EmailSubscriptions extends Component {
    constructor(props) {
        super(props);

        this.state = {};
    }

    componentDidMount() {
        this.props.actions.getEmailSubscriptions();
        this.setState({    // Not setting state
                notifications: [
                    newsletter = this.props.newsletter,
                    orderConfirmation = this.props.orderConfirmation,
                    shippingInformation = this.props.shippingInformation,
                    orderEnquiryConfirmation = this.props.orderEnquiryConfirmation
                ]
            })
    }

    render() {
        return (
            <div>
                Here I want to use loop through state to create checkboxes
                {this.state.notifications&& this.state.notifications.map((item, index) => {    
                        const checkboxProps = {
                            id: 'subscription' + index,
                            name: 'subscription',
                            checked: item.subscription ? true : false,
                            onChange: (e)=>{ return this.onChange(e, index)},
                        };

                        return <div key={index}>
                                    <Checkbox {...checkboxProps} />
                                </div>
            </div>
        )
    }
}
export default EmailSubscriptions;

Solution

  • I hope getEmailSubscriptions is an async action, so your setState won't update the state as you intended. add componentDidUpdate hook in your class component and your setState statement within an if statement that has an expression checking your props current and prev value.

    You can do something like this.

      componentDidMount() {
        this.props.actions.getEmailSubscriptions();
      }
    
      componentDidUpdate(prevProps, prevState, snapshot){
        if(this.props.<prop_name> != prevProps.<prop_name>){
          this.setState({ 
            notifications: [
              newsletter = this.props.newsletter,
              orderConfirmation = this.props.orderConfirmation,
              shippingInformation = this.props.shippingInformation,
              orderEnquiryConfirmation = this.props.orderEnquiryConfirmation
            ]
          })
        }
      }