i have a problem with react i need to setstate a spesific user when i click at button "succeed" it will change the object inside to false this is the deatils first i have an array of object (users) and object that called "workoutDeatils" inside this object i have 3 object the last one on index 2 is called "workout" inside this workout i have a object of all the workout and i need to change it spesific the problem when i want to use the setstate of users on the change it dosent work (because it gets confused) what i need to do is: change status to false this one i know but how i will setstate the users with the map? it should be nasted loop?
import HomePage from "./componente/HomePage";
import React, { useState } from "react";
import WorkoutDeatilsField from "./componente/WorkoutDeatilsField";
import SpesificUser from "./componente/SpesificUser";
import Workout from "./componente/Workout";
import { BrowserRouter, Route, Routes } from "react-router-dom";
function App() {
const [users, setUsers] = useState([]);
const [spesificUserId, setSpesificUserId] = useState(0);
const [spesificWorkOut, setSpesificWorkout] = useState();
const spesificUser = users.find((user) => {
return user.id == spesificUserId;
});
const getWorkoutDeatils = () => {
const { workout } = spesificUser.workoutDeatils[2];
const spesificWorkoutPlane = workout.find((workout) => {
return workout.workoutNum == spesificWorkOut;
});
return spesificWorkoutPlane;
};
const findUserExists = (id) => {
const checkUserExists = users.filter((user) => {
return user.id == id;
});
return checkUserExists.length !== 0 ? true : false;
};
const addUser = (id, fullName, gender) => {
const user = {
id: id,
fullName: fullName,
gender: gender,
};
setUsers((prev) => {
return [...prev, user];
});
};
const setTraning = (trainWeek, trainInYears) => {
const workoutInWeeks = new Array(Number(trainWeek)).fill(1);
let kmcacluator = (trainInYears * 5) / trainWeek;
const workoutDeatils = [
{
trainWeek: Number(trainWeek),
},
{ trainYears: Number(trainInYears) },
{
workout: workoutInWeeks.map((workout, index) => {
kmcacluator = kmcacluator (kmcacluator / 100) * 15;
return { workoutNum: index 1, km: Math.ceil(kmcacluator), status: true };
}),
},
];
const afterMap = users.map((user) => {
return user.id == spesificUserId ? { ...user, workoutDeatils } : { ...user };
});
setUsers(afterMap);
};
const get = ()=>{
const afterMap = users.map((user)=>{
})
}
return (
<div className="App">
<BrowserRouter>
<Routes>
<Route
path="/"
element={
<HomePage findUserExists={findUserExists} addUser={addUser} setSpesificUserId={setSpesificUserId} />
}
></Route>
<Route
path="/workoutdeatilsfield"
element={<WorkoutDeatilsField spesificUser={spesificUser} setTraning={setTraning} />}
></Route>
<Route
path="/traning/:id"
element={<SpesificUser setSpesificWorkout={setSpesificWorkout} spesificUser={spesificUser} />}
></Route>
<Route path="/workout" element={<Workout getWorkoutDeatils={getWorkoutDeatils} />}></Route>
</Routes>
</BrowserRouter>
<button
onClick={() => {
console.log(users);
}}
>
Click
</button>
</div>
);
}
export default App;
{
"id": "1",
"fullName": "dsa",
"gender": "male",
"workoutDeatils": [
{
"trainWeek": 3
},
{
"trainYears": 2
},
{
"workout": [
{
"workoutNum": 1,
"km": 4,
"status": true
},
{
"workoutNum": 2,
"km": 5,
"status": true
},
{
"workoutNum": 3,
"km": 6,
"status": true
}
]
}
]
}
this is an example how it add user with his deatils
CodePudding user response:
React's setState
doesn't re-render the component if the state does not change. "state change" means you call setState
with a value different from the previous one. "different" means it is not strictly equal (===
) to the previous one. In JavaScript objects are compared by reference, so in order to change an object with setState
you have to set a new object.
Thankfully, setState
can receive a function that takes the previous states and computates the next one, particularlly useful for your use case when you want to update a nested property of an object. The key here is that you have to declare a new object and put all the data of the old object into the new one, changing only the value you want to change. With some spreading (...
) and array methods (filter
, find
) you can easily, for example, toggle the status of the third wourkout.
const workoutNum = 3 // Or whatever workout you want to change
setUser(previous => {
const workoutToChange = previous.workoutDetails[2].workout
.find(d => d.workoutNum === workoutNum)
return {
...previous,
workoutDetails: [
...previous.workoutDetails.filter(details => !details.workout),
{ workout: [
...previous.workoutDetails[2].filter(w => w.workountNum === workoutNum),
{ ...workoutToChange, status: !workoutToChange.status }
]}
]
}
})