Correct way to update a state array in a Flux Store - reactjs

I have a Flux Store and a state array that needs updating when a new comment is created so that a list of comments updates in the view. I just want to confirm that I am updating it correctly using push:
this.state.comments.push(commentArray);
It works fine but I have read about immutability but as this is a store and not a view I take it this is ok?
onDispatcherAction: function (payload) {
var action = payload.action;
if (ActionTypes.CREATE_CONFIGURATION_SETTINGS_RESPONSE === action.type) {
this.handleResponseErrors(action.data);
var commentArray = {
_id: action.data._id,
user: {
id: action.data.user.id
},
id:action.data.id,
commentname: action.data.commentname,
timeCreated: action.data.timeCreated
}
this.state.commentname = action.data.commentname;
this.state.comments.push(commentArray);
this.emitChange();
}
}

You probably should take a look to the Immutability Helpers.
From React Documentation
Simple push
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray is still [1, 2, 3].

Related

How do I add new values to state using Typescript?

you need to add new values to the array, I can't understand what the problem is.
When you click on a checkbox, you need to get the id of this checkbox and write it to the array of answers for the corresponding question
type Result = number;
interface Answer {
result: Result[];
}
const answers: Answer[] = [];
questions.forEach(() => {
answers.push({
result: [],
});
});
const [currentAnswer, setNewAnswer] = useState<Answer[]>(answers)
const handleChange = (e:React.ChangeEvent<HTMLInputElement>) =>{
// console.log(typeof(currentAnswer),currentAnswer);
if(e.target.checked){
console.log(currentAnswer[currentQuestion].result.push(Number(e.target.id)));
setNewAnswer(
currentAnswer[currentQuestion].result.push(Number(e.target.id) // ERROR HERE
)
...
I got error
const currentAnswer: Answer[]
// Argument of type 'number' is not assignable to parameter of type 'SetStateAction<Answer[]>'
should use .concat() in this situation to return new array
.push() will only return new length which is number and incompatible with the type you make.
setNewAnswer(
currentAnswer[currentQuestion].result.concat(Number(e.target.id)) // ERROR HERE
)
To expand on Mic Fung's answer, push mutates the existing array and doesn't return the new array.
const myArray = [1, 2, 3]
myArray.push(4) // returns 4, which is the new array length
console.log(myArray) // [1, 2, 3, 4]
concat doesn't mutate the existing array, but instead returns a new array
const myArray = [1, 2, 3]
const myNewArray = myArray.concat(4)
console.log(myNewArray) // [1, 2, 3, 4]
console.log(myArray) // [1, 2, 3]
When working with React, you should avoid directly mutating the state. Instead, create new values and pass them to the setState function. This is why functions like concat are preferred over ones like push, as they avoid the mutation.

deleting data from react-table

I am using react-table.js to take data from a form, but I want to be able to delete the data out of the table. The button is working so I know that is attached properly, but I can't seem to get it to delete.
Here is the code
handleDelete = item => {
var newArr = [];
const newState = this.props.documentation;
for (var key in newState) {
if (newState.hasOwnProperty(key)) {
let data = newState[key];
data.id = key;
newArr.push(newState[key]);
}
const sliceArr = newArr.slice();
if (sliceArr.indexOf(item) > -1) {
sliceArr.slice(sliceArr.indexOf(item), 1);
}
console.log('New Array', sliceArr);
this.setState({ data: sliceArr });
}
};
Along with the button I am attaching it to
Cell: row => (
<div>
<button onClick={() => this.handleDelete(row.id)}>Delete</button>
</div>
You're looking for splice rather than slice:
const spliceArr = newArr.slice();
if (spliceArr.indexOf(item) > -1) {
spliceArr.splice(spliceArr.indexOf(item), 1);
}
console.log('New Array', spliceArr);
this.setState({ data: spliceArr });
Example:
const newArr = [1, 2, 3, 4]
// [1, 2, 3, 4] example
const spliceArr = newArr.slice()
// [1, 2, 3, 4] ok
spliceArr.slice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 3, 4] oops
spliceArr.splice(spliceArr.indexOf(3), 1)
spliceArr
// [1, 2, 4] better
If that doesn't get you all the way there, you may want to update your question with the rendering (presumably JSX) of the table itself, as #MichaelBenin suggested.

How to mute the state in reactjs

I am having a issue in reactjs state management .Everytime component loaded it loads the data from cache.I done research over that and found that state is immutable.I want to ask how to use immute the state.
Currently it is like i took a empty array in state in constructor then I called a api in component will mount and set that state to response but untill and unless Indont clear cache, state is not showing the data
Guide me where I am making mistake here or how can I immute the state
Mutating an object: Use the Object.assign({}, ...)
var yourCar = {
color: 'red',
.. the same as neighboursCar
};
var neighboursCar = {
color: 'red',
... the same as yourCar
};
yourCar.color = 'blue'; // reference stays the same!
var yourCarRepainted = Object.assign({}, yourCar, { color: 'blue' });
yourCarRepainted === yourCar; // false
Mutating an array: Use [].concat
var list = [1, 2, 3];
var list = [1, 2, 3];
list[1] = 4;
var list = [1, 2, 3];
var changedList = [].concat(list);
changedList[1] = 4;
var list = [1, 2, 3];
var changedList = [].concat(list);
changedList[1] = 2;
list === changedList; // false
this.state and this.setState({}) in React is already immutable.
You can also try immutable.js 3rd party library to get a better grasp on this subject.

Updating / inserting a nested object React / Redux [duplicate]

This question already has an answer here:
Update a nested state in redux
(1 answer)
Closed 5 years ago.
I have a JSON object in an array in my Redux store
editor: [] 1 item
0: {} 1 key
flow {} 3 keys
id: "1234"
name: "qaz"
tasks: [] 5 items
What is the best way to update or insert a new tasks array
My actions is
export function insertTasks(tasks) {
return {
type: 'INSERT_TASKS',
tasks
};
}
And the Reducer is
case 'INSERT_TASKS':
state[0].flow.tasks = [];
state[0].flow.tasks = action.tasks;
return state;
I'm passing it the action.type and action tasks correctly and I appear to be updating the tasks array inside my object. But this reducer code just doesn't feel correct.
When I add a completely new flow my reducer is
case 'ADD_FLOW':
state = [];
return [
...state, {
// index: 1,
flow : action.flow
}
]
which feels much better.
So I suppose I looking for the best way to access deep arrays in Redux .
You can continue using the spread syntax as deep as you want. For example given this:
var o = {
foo: bar,
baz: {
id: 1,
title: 'title',
description: 'description'
},
bang: [1, 2, 3]
};
then returning this:
return {
...o,
baz: {
...o.baz,
description: 'new description'
},
bang: [...o.bang, 4, 5]
};
will result in this:
{
foo: bar,
baz: {
id: 1,
title: 'title',
description: 'new description'
},
bang: [1, 2, 3, 4, 5]
}
You want to avoid reassigning or mutating anything in your reducers. To achieve this, assuming you only ever have a single item in your state array, you could do something like:
case 'INSERT_TASKS':
return [{
...state[0],
tasks: actions.tasks,
}];
What the spread (...) operator is doing here is taking all of the keys from state[0] and creating a NEW object with all the same keys currently in state[0] after which we are replacing the tasks key with the new tasks array.

Redux - How to add entry to array in reducer

I stuck with this bit and I can't progress - I guess solution is simple but I can't figure out. I'm trying to add entry in reducer so data in in would look something this:
state = {
entryId: {
entryName: ["something", "something2", "something3" /* and so on... */]
}
};
So far this is the closest I get, but, instead of adding new unique entry, it is replacing the one that is stored already. Also I need to be able to add this item to empty state where entryId, entryName doesn't exist yet to avoid error:
switch(type) {
case ADD_ENTRY:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: {
[uniqueEntry]: true
}
}
};
}
Any idea what I'm doing wrong?
If you're trying to add an element to the end of the entryName array you should be doing:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: [
...state[entryId][entryName],
uniqueEntry
]
}
};
ES6 spread with arrays works like this:
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const eight = 8;
const newArray = ['stuff', ...array1, 'things', ...array2, ...[7, eight], 9];
console.log(newArray); // ["stuff", 1, 2, 3, "things", 4, 5, 6, 7, 8, 9]
Check out this gist which has an example of something very similar to what you're doing.
I found this set of examples extremely helpful as well. A lot of great stuff in here:
https://github.com/sebmarkbage/ecmascript-rest-spread
Update:
If entryName is initialized to undefined like you say in your comment, you could do this:
return {
...state,
[entryId]: {
...state[entryId],
[entryName]: [
...state[entryId][entryName] || [],
uniqueEntry
]
}
};
I think this is a pretty great example of how painful it can be working with React/redux using a heavily nested data structure. FWIW, it's been recommended to me many times to flatten your state as much as possible.

Resources