Redux data not rerendering when setting value within object (Immutable.js) - javascript

I have an immutable.js Map stored in Redux that is structured like:
reduxObject: {
details: {}
...
objectToChange: {
myPosts: [{
name: 'someName',
link: 'someLink',
}],
drafts: []
}
}
I am trying to append the array objectToChange.myPosts in a reducer function using
let temp = state.getIn([objectToChange, myPosts])
temp.push(action.payloadData)
return state.setIn([objectToChange, myPosts], temp)
The redux data is getting updated, however the displayed redux data isn't getting rerendered. I was expecting the state.setIn to create a new immutable object causing react native to trigger a rerender. Any suggestions or help would be greatly appreciated. Thanks ahead of time

So I found a workaround to using immutable that i'm not sure is acceptable but it works. I am now using lodash's cloneDeep function.
let temp = _.cloneDeep(state)
temp[action.payloadType][action.payloadLoc].push(action.payloadData)
return (temp)

Ok so cloneDeep was a bad workaround but i found the proper solution to the problem. I needed to return the statement like this:
case 'postNewItemFbData':
let tempUpdate = state[action.payloadType][action.payloadLoc]
tempUpdate.push(action.payloadData)
return {
...state,
[`${action.payloadType}.${action.payloadLoc}`]: tempUpdate
}

Related

Angular ngrx: TypeError: Cannot freeze array buffer views with elements

Im encountering an issue with ngrx. I have an array in my state to which i want to append objects. This actually works fine if i console.log them i can see that values in my store. But the redux dev tools and the console throw the error "TypeError: Cannot freeze array buffer views with elements".
I have a state that looks like this:
const state: State = {
array: []
};
The Object i pass to my actions looks similar to this:
const obj = {attr: number, data: ImageData};
Where ImageData comes from a Canvas and is extracted with canvas.getContext("2d").getImageData(...);. It should be noted that this Object is huge with over 69000 keys with values from 0 to 255(RGBA).
And i append the new Object to the state/store like this:
createReducer(
initialState,
on(action, (state: State, action)=> {
return {
...state,
array: [...state.array, action.payload]
}
})
);
Furthermore i read that i should deepCopy Objects before passing them to the action so i did that with lodashs copyDeep(), but i got the same results.
Any help is appreciated.
You need state.array in your reducer.
return {
...state,
array: [...state.array, action.payload]
}
I had the same problem, I solved it by cloning the data that I pass to the dispatch method
ex:
const dataCloned = CloneDataInDeep.clone(dataToAdd);
this.store$.dispatch(actionToDispatch({ dataCloned}));
Another option that I have tried is to change this attribute value "strictActionImmutability" in the ngrx configuration from true to false
runtimeChecks: {
strictActionImmutability: false,
....
}
I use Angular and came across that error.
For me, deep copying the array before the dispatch worked
const copyArray = JSON.parse(JSON.stringify(array));
this.store.dispatch(actionDispatch.requestSth({ myArray: copyArray }));
Not the most beautiful solution, I know.
Edit:
Unfortunately the solution was not helpful because the objects inside the array lose the functions when strigified... So back to square one
You can use this code. This will copy the entire object so the dependency will be removed.
const newlyCreatedArray = Object.assign({}, array);
For more details: Object.assign()

How to clear array which is inside nested state?

I have crated state like below and at some point I want to clear this array and update with new one. I used below code for clearing, but when I check state through react-developer tool, array is still there nothing is happening. Please help me as my newbie to ReactJS.
state = {
formData:{
level:{
element:'select',
value:'Bachelors',
label:true,
labelText:'Level',
config: {
name:'department',
options: [
{val :"Bachelors", text:'Bachelors'},
{val:"Masters", text:'Masters'}
]
},
validation: {
required:false,
}
,
valid:true,
touched:false,
validationText:'',
},
Now I want to clear options array by:
let {options} = this.state.formData.level.config
options = []
this.setState({
options:options
})
But my array is not clearing. How can I achive that?
Two things that you should know.
1) When you do this.setState({ options: options }), you are not updating the options array belonging to the formData object. You are creating a brand new key-value pair in your state called options. If you try to print your updated state, you will find that your state now looks like:
state = { formData: {...}, options: [] }
2) You are trying to directly mutate state, (changing a value belonging to the existing object). This is against React principles, because in order for the component to re-render correctly without being prone to side-effects, you need to provide a brand new state object.
Since its so deeply nested, the likely best option is to deep clone your state-object like this:
const newFormData = JSON.parse(JSON.stringify(this.state.formData))
newFormData.level.config.options = []
this.setState({
formData: newFormData
})
This will probably be the safest way to clear your form data object. Here's a working sandbox with this feature as well. Please use it for reference:
https://codesandbox.io/s/naughty-cache-0ncks
create newstate and change properties then apply the new state to setState() function like this:
changestate = ()=>{
var newstate = this.state;
newstate.formData.level.config.options=["hello","wow"]
this.setState(newstate)
}
You are not clearing the options state but creating a new state with an empty array.
You can either clone the whole object using JSON stringify and JSON parse too . Other way to update nested states without mutation is by using spread operators. The syntax looks a bit complex though as spread nested objects while preserving everything is tricky.
const newFormData = {
...this.state.formData,
level: {
...this.state.formData.level,
config: {
...this.state.formData.level.config,
options: []
}
}
};
this.setState({
formData: newFormData
})

Updating Object Property in Reducer without Mutation

I feel like my reducer should be working, but it keeps insisting that I'm mutating the state.
Uncaught Error: A state mutation was detected inside a dispatch, in the path: output.outputList.0.composition. Take a look at the reducer(s) handling the action {"type":"SET_OUTPUT_COMPOSITION",
I posted something similar a couple hours ago with no answers, but I figured my redux state was too complicated. This is my simplified version and I'm still getting mutate errors.. what am I doing wrong? should I not be using a class in my redux state? should i be using some sort of immutable library? please help me.
My Initial Redux State
output: {
outputList: [], //composed of Output class objects
position: 0
}
Output Class
class Output {
constructor(output) {
this.id = output.id;
this.composition = output.getComposition();
this.outputObj = output;
this.name = output.name;
this.url = output.getUrl();
}
}
export default Output;
Reducer for updating property
case types.SET_OUTPUT_COMPOSITION: {
let outputListCopy = Object.assign([], [...state.outputList]);
outputListCopy[state.position].composition = action.composition;
return Object.assign({}, state, {outputList: outputListCopy});
Action
export function setOutputComposition(comp) {
return { type: types.SET_OUTPUT_COMPOSITION, composition: comp}
}
The spread operator does not deep copy the objects in your original list:
let outputListCopy = Object.assign([], [...state.outputList]);
It is a shallow copy, therefore
outputListCopy[state.position].composition = action.composition;
You are actually mutating previous state objects, as you said in your comment there are several ways to work around this, using slice/splice to create new instance of the array, etc.
You can also take a look at using ImmutableJS, in general I would say storing classes in the redux store makes the thing a bit hard to understand, I tend to favor simple structures that can be easily inspected with redux-tools.
The error is coming from dispatch. So it not even getting as far as the reducer. I expect it does not like you using class to define output. Instead just do const output ={ ... }.

Redux/React-Redux - using "state = XXX" in the reducer

We're using Redux.js with React.js (React-Redux), and in the reducer we're using the following code (we are using redux-actions to reduce boilerplate):
const update = require('react/lib/update');
const myReducer = handleActions
({
[myAction]: (state, action) => {
state = update(state, {
something: {$set: !state.someProperty}
});
return someFunction(state);
}
})
We are using update from React Immutability Helpers but assigning the result into the state using state =.
Is this against the basic Redux guidlines - i.e. mutating the state? It seems so, but the code seems to work perfectly and quickly, and the redux devtools shows the state changes correctly...
Your example is okay, because you're not actually mutating the contents of the object that the state variable points to. Instead, you're just updating the local variable named state to point to a different object instead.
It's important to understand how variables and references work in Javascript, which will help clear up what's going on here.
Personally, I'd suggest doing const newState = update(....) for clarity.

Vue.js - Add or set new data to array in store

I have two Vue components that use a common array set in a store like this:
var store = {
state: {
myArray: []
}
};
var FirstComp = Vue.extend({
template: '#first-template',
data: function () {
return {
arrayData: store.state.myArray
};
}
});
/* A second component quite identical */
I followed the example given in the Vue js guide.
I'm trying to update the data in the array in the store with new data from another array (after an ajax call), so that it impacts both components. I would like to have a nice way of replacing / concating the old array with a new one. I know I can't just replace the array like this store.state.myArray = newArrayData;because I would loose the Vue binding. But the method given in the docs (at least for concat) doesn't work in the case of the store (or maybe I'm missing something?).
Right now, the only way I've found is to use a foreach with push, $removeor $set depending on the operation and it is not that elegant and practical.
For example, for concat, I do this:
$.each(newArray, function (i, val) {
store.state.myArray.push(val);
});
But for replacing it gets uglier. What would be the proper way to this?
(For info, I'm not using Vuex for state management and I don't plan to at the moment, I'm keeping it very simple)
To make the assignment work you can just use "state" in your component like this:
var FirstComp = Vue.extend({
template: '#first-template',
data: function () {
return {
state: store.state
};
}
});
And then use state.myArray. This way if you will do store.state.myArray = newValue it won't break the binding.

Categories

Resources