issues with redux payload in reducers - javascript

I have the following code for one of the CASES in reducers
case CHART_CHANGE: {
const {method,copiedArray} = payload;
let ref = copiedArray
let swapped = bubblesort(copiedArray) //<------here
console.log(ref)
console.log(swapped)
}
}
The question is this, as you can see here I assigned the variable ref before involving the bubblesort function. But when I run the program, ref variable has the same value with the swapped variable. Why is that?

In javascript objects (arrays are objects) are assigned by reference, so copiedArray and ref are referring (pointing) to the same object. If you change the contents of the object (and your bubblesort function seems to sort in place - that is mutate/change the array internally), the changes are visible in all of the variables: copiedArray, ref and swapped.
const copiedArray = [3,2,1];
const ref = copiedArray;
const swapped = copiedArray.sort();
console.log(copiedArray);
console.log(ref);
console.log(swapped);

Related

Redux modifying the a state value without being asked to?

i'm using redux to manage my state , my initial state in the reducer contains to arrays !
the first one(games) is the one that i want to modify , the second one (InitialGames) is Initial one that i don't want it to be modified !
the problem is i only make changes on the first array ! but when i console my state after the logic ! i see that both arrays got changed ??? which is confusing !
The case that i'm going into is PLAYER_DEAD
My Reducer
import { ADD_GAME, PLAYER_DEAD, PUT_INFOS, RESET_GAME } from "./actions";
const initialState = {
games: [],
InitialGames: [],
};
export default (state = initialState, action) => {
switch (action.type) {
case RESET_GAME:
state.games[action.payload.gameIndex] =
state.InitialGames[action.payload.gameIndex];
console.log(state);
return state;
case ADD_GAME:
return {
games: [...state.games, action.payload.game],
InitialGames: [...state.games, action.payload.game],
};
case PUT_INFOS:
return {
gameInfos: action.gameInfos,
};
case PLAYER_DEAD:
let newGames = state.games;
let newInitialGames = state.InitialGames;
console.log("Before Changings", newGames, newInitialGames);
let newTeam = newGames[action.payload.indexGame].teams[
action.payload.index
].players.splice(0, 1);
console.log(
"After changings",
newGames,
newInitialGames
);
return {games:newGames,InitialGames:newInitialGames};
}
return state;
};
This would be occurring because you're passing the same action.payload.game object to both of your arrays here:
return {
games: [...state.games, action.payload.game],
// same objects ---------^------v
InitialGames: [...state.games, action.payload.game],
}
When you access the .teams array in your PLAYER_DEAD case, you're accessing the same array in memory shared by both games and InitialGames, the same goes for anything within that array, including the .players array within your .teams array's objects. Because you're updating your array in place in a non-immutable way by using .splice(), you end up modifying your state directly and thus modifying the same .players array referenced by both games and InitialGames.
You need to ensure that you don't modify your state in place by using methods like .splice(). For your particular case, you would do something like so:
const newGames = state.games.map((game, i) => i === action.payload.indexGame
? game.teams.map((team, j) => j === action.payload.index
? {...team, players: team.players.slice(1)} // note slice, not splice
: team
)
: game
);
Above, we map your arrays, updating the items when the inndx matches the item to update. When updating the players array, we use .slice() to remove the first item from the array.
Writing immutable code isn't always easy, that's why redux toolkit has built-in support for immer when you use an API such as createSlice() API that will allow you to write code like you've been doing the mutates your state. See here for more info.

Destructuring in JavaScript while using React

I came up with the following questing while I was trying to make a TODO app using React.js
I was trying to make and update functionality for each task. For that, I made a button which on click, calls a function "update" which calls a function passed as a prop defined in App.js, this function iterates through the tasks array find the one to modify and does its thing, then it sets the new state
App.js
function App() {
const [taskItems, settaskItems] = useState([]);
const updateTask = (task,newname) =>{
const findAndModify=()=>{
let tasks = [...taskItems] // Why let task=taskItems doesnt work?
for (let index = 0; index < tasks.length; index++) {
const t = tasks[index];
if (t.name === task.name){
t.name = newname
}
}
return tasks
}
settaskItems(findAndModify())
}
}
My TaskRow component is the following
<TaskRow task={task} key={task.id} toggleTask={toggleTask} updateTask={updateTask}></TaskRow>
Inside the definition of my TaskRow.js component I have the following code
export const TaskRow = (props) => {
const update = () => {
const newname = "hello";
props.updateTask(props.task, newname);
};
return (
<tr key={props.task.id}>
<td>{props.task.name}</td>
<td>
<input
type="checkbox"
checked={props.task.done}
onChange={() => props.toggleTask(props.task)}
/>
</td>
<td>
<button className="btn btn-success mx-1" onClick={update}>
Actualizar
</button>
</td>
</tr>
);
};
the question comes here, if in findAndModify instead of doing let tasks = [...taskItems] I do task=taskItems the description of the updated task does not re-render until another change happens, but if a do a console.log of the data, it indeed, had been modified
why is that? how does the [...] operator differs of a regular variable assignment?
I've researched about destructuring in JS but nobody talks about some kind of difference between the use of this operator and a regular var assignment in React.js
The difference between:
(1) method:
let tasks = [...takItems];
(2) method:
tasks = taksItems
is the behavior of javascript with Objects type (for ex. Array)
when you assign a variable to an array it creates a reference and not a shallow copy.
So if you use the (2) method and change tasks variable, it will be reflected in tasksItems, if you use the (1) method, you will have 2 independence variables!
React indicates to NEVER mutate a state directly, like you did when using the (2) method and treat it as immutable type.
You can read more about it here
Why we should never update React state directly
To expand a little bit more, the spread operator [...takItem] makes a shallow copy, which means that it will be a new copy of the variable, but because it is 'shallow' any nested non-primitive data will all be pointers. E.g.,
const tasks = ['a', 'b', { subtask: 1 }]
const shallowCopy = [...tasks]
shallowCopy[0] = 'A'; // won't change the value of tasks
shallowCopy[2].subtasks = 'C'; // does change the values of tasks
console.log(tasks)
// ['a', 'b', 'C']
In the example above, the third item in the tasks array is non-primitive (also known as "reference" type), so shallowCopy[2] is just a pointer to the same place in memory as tasks[2]. tasks[2] and shallowCopy[2] are both referencing the same piece of data, which is why when you modify shallowCopy[2].subtasks it also modifies tasks[2].subtasks

How to copy object to new variable

Let's say I have class called Person, which have firstName, lastName, and Array of addresses fields.
And in one of my angular components I am getting Person object to do some operation on them. But I would like to create two copies of this obj. To do that I am using Object.assign. But after that when I am manipulating firstName from firstCopyPerson all other objects are changed too.
How can I assign object to new variable without making reference to orginal object, but instead just creating new separate object?
mainPerson: Person;
firstCopyPerson: Person;
secondCopyPerson: Person;
ngOnInit() {
this.mainPerson = someCache.getPerson();
this.firstCopyPerson: Object.assign({}, this.mainPerson);
this.secondCopyPerson: Object.assign({}, this.mainPerson);
}
You can add this re-usable function so you can reuse this function everytime
const copyObject = (obj) => {
let result = {};
Object.entries(obj).forEach(([key, value]) => {
result[key] = value;
});
return result;
};
// Test the function
const obj1 = {name: 'notebook', price: 100};
objCopy = copyObject(obj1);
console.log(objCopy);
You can also use this way
const obj = {name: 'laptop', price: 100};
// This is the implementation line
let objCopy = {...obj};
console.log(objCopy);
whenever you use this code you are assigning a new reference to the object and both variables assigning to the same object so when you edit one of them the other will change too. you can solve this by destructing the object for example you can try this :
let personCopy = {...person}
Object.assign would only make a shallow copy of the object, that means all attributes are assigned to the same data objects.
You may want to read about deep copies which are the safe way to go.
Fenton already posted a brilliant answer to this, take a look at option 4 in his answer:
https://stackoverflow.com/a/28152032/8341158

Best way to reference an object property

Let say I have an object with
let product =
{ id:1,
model:2
}
I can reference the id by
const productId = product.id
Or I can also do
const newProductCreated = Object.assign({}, product)
then reference by newProductCreated.id
Which would be the best way for me to reference the id?
If you are working with the Redux/'Flux' methedology, the second method makes sense, it is not how you should be using it.
Assuming you are trying to create a shallow copy of the object, you can simply do this:
const productCopy = { ...product };
// or const productCopy = Object.assign({}, product) if you can't support ES6
From there, you can make respective changes to the properties within productCopy without affecting the original product.
productCopy.model = 3;
// console.log(productCopy) prints out the modified object
// console.log(product) prints out the original object
This will be conform to the immutable update patterns.

reactjs changing object attributes inside the state object

I get an object as response from a get.
Now I assign the object to a state var (object) like this:
this.setState({editData: response.data})
Is there a way to change the values within this object?
I thought about something like this:
this.setState({editData.[var]: [value]})
thanks
Firstly you have to remember that you should never mutate state object directly. So first you shold make a copy of state object and mutate the copy. Then set this copy as state. You can use spread syntax to achieve it:
this.setState((prevState) => ({editData: {...prevState.editData, [var]: value}}));
Here is working example showing that source object is not mutated:
let state = {
editData: {
age: 22
}
};
let age = "age";
let stateCopy = {editData: {...state.editData, [age]: 100}};
console.log(state);
console.log(stateCopy);

Categories

Resources