Reputation: 14821
I am developing a Web application using React and Redux as the front-end JavaScript framework. I am having a bit of a problem with rendering view and updating the Redux state/store value.
I have an input field which update the Redux state value. This is the event handler for onChange of my text field.
_handleNameInput= (event) => {
this.props.updateField({
name: 'name',
value: event.target.value,
})
}
In the reducer I am updating the field of the state like this
case RESTAURANT_CATEGORY_UPDATE_FIELD: {
let freshState = { ...state };
_.set(freshState, action.payload.name, action.payload.value);
return freshState;
}
I am using Lodash to update the field of the state object.
This is my default state
let defaultState = {
name: ''
}
When the user is entering the input, I display the live state value on the view like this.
<h1>Name is: {this.props.name}</h1>
The above scenario works totally fine. It is displaying the live changes while I am changing the value of the input as well. The problem began when I use the nested object in the state. I updated the defaultState to this.
let defaultState = {
form: {
name: '',
}
}
Then in the callback, I update like this.
this.props.updateField({
name: 'form.name',
value: event.target.value,
})
It is updating the redux state/store values of the nested property of the object. The problem is that when I display the live changes like this
<h1>{this.props.form.name}</h1>
It is not updating/rendering the view. How can I fix it?
Upvotes: 3
Views: 2632
Reputation: 1
just because I was browsing this The immer thing looks cool but u can also just set a property off and on at the shallow end of your state
state.something.somethingelse = {
...state.something.somethingelse,
updatedItem: posts,
forceReRender: !state.something.somethingelse.forceReRender
};
or
state.forceRender = !state.forceRender
Upvotes: 0
Reputation: 5707
When you connect your component to redux via the connect
function your component behaves as a PureComponent
. That is, it will perform a shallow check of the new props, comparing them to previous props, to see if the component should perform an update.
In the first instance name
is a top-level prop and it's change is detected so the update is performed.
In the second instance form
is the top-level prop which has not changed so the update is prevented.
As suggested in the comments, you can use immer
to ensure that the form
object is replaced with a new object with the updated name
property.
import produce from "immer";
return produce(state, draft => {
_.set(draft, action.payload.name, action.payload.value);
});
In the second case it would effectively do the following..
return {
...state,
form: {
...state.form,
name: action.payload.value
}
};
I would suggest though, that you reconsider having an action and reducer which update arbitrarily deeply nested fields and instead use something more specific.
RESTAURANT_CATEGORY_UPDATE_FORM_FIELD
return {
...state,
form: {
...state.form,
[action.payload.name]: action.payload.value
}
};
or
return produce(state, draft => {
draft.form[action.payload.name] = action.payload.value;
});
Upvotes: 5