0
votes

I am trying to set a deeply nested object in my react.js/redux app via a reducer, but the object changes are not propagating down to my component. How should I update and mapStateToProps an object like this?

I have tried ...ing my action's payload in my reducer, mapping a higher level object in my mapStateToProps, and flattening the object I map to my components props.

My initial state:

const initialState = {
    myObject : {
        prop1 : {
            prop2 : {
                array1 : [],
                array2: [],
                array3: []
            }
        }
    }
}

My reducer:

const app = (state = initialState, action) => {
  switch(action.type) {
    case SET_DATA:
      return {
        ...state,
        myObject: action.payload
      };
  } default:
      return state;
}

export default app;

My Component:

class Component extends React.PureComponent() {
    render() {
        return (
            {
                JSON.stringify(this.props.componentObject)
            }
        );
    }
}

function mapStateToProps(state) {
    return {
        componentObject: state.myObject
    };
}

export default connect(mapStateToProps)(Component);

Action creator for updating nested object

export function setData(newDeeplyNestedObject) {
  return {
    type: SET_DATA,
    payload: newDeeplyNestedObject
  };
}

The result is that my Component is not displaying what is in Redux's state. It appears that the Redux is not detecting a change in my components props thus not updating the Component. Can anyone tell me how to make sure Redux sends updates to my component when a deeply nested object structure changes?

I know that Redux does a shallow compare for updates, but I feel like a JSON.parse(JSON.stringify()) in my reducer is not the right direction here.

1
your mapStateToProps is incorrect, myObject is inside state.app but you are looking for it in state. You need to do: componentObject: state.app.myObjectVaibhav Vishal

1 Answers

0
votes

1) Implement a store by: import {createStore} from "redux"; export const store = createStore(app) // you pass in your reducer name

2) In mapStateToProps, access your myObject state like: function mapStateToProps(state){ return{ myObject:state.myObject } };

3) Bind your action dispatcher:

   import {bindActionCreators} from "redux";
   const mapDispatchToProps = dispatch =>(bindActionCreators({setData}, dispatch));
   //Now we can use the setData action creator as this.props.setData()

4) Use both mapStateToProps and mapDispatchToProps and connect it to the component:

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

5) Suppose you defined myObjects in INITIAL_STATE, for example:

    myObject : {
        prop1 : {
            prop2 : {
                array1 : [{a:'1'},{b:'2'}],
                array2: [{q:'6'},{w:'4'}],
                array3: [{m:'9'},{n:'0'}]
            }
        }
    }
};

6) Now you need to fire your action function setData using any changeHandlers or button press and pass the newObject which you wanna add as arguments. The idea is to spread the objects(using the ... operator) and append the new items which you wanna add. Suppose you wanna fire your action on an onClick event and change the array1 values:

<input type="button" onClick={()=>this.props.setData({...this.props.myObject.prop1.prop2,array1:[{changedA:'21'},{changedB:'32'}]})}/>

This will fire the action, and only the array1 will be changed. Similarly, you can do for any nested objects. Whatever change you want to do, you have to spread your objects and then append the new items

PS: Also enclose the return in tags.