While updating the variable with index, all the objects with the same key but different index also changing in react js

Viewed 52

I tried to change the array of objects, actually, I created a task list that has user name, task description, and so on while updating the first index task, all the objects with different array indexes are also changing. I tried to recognize for long, but can't able to catch what's going actually,

Reducer.js

import actions from "./actions";
const stateInit={
    taskCount:0,
    taskDetails:[],
    templates:[],
    save:false,
    edit:false,
    createTask:[],
    userData: {
            task_msg: '',
            task_date: '',
            task_time: 36000,
            assigned_user: '',
            time_zone: new Date().getTimezoneOffset(),
            is_completed: 0,
        }

};
export default function tasks(state=stateInit, action){
    switch (action.type){
        case actions.ON_CREATE_TASK:{
            const {taskCount,save}=action.payload;
            console.log("create task", state.createTask)
            return {
                ...state,
                taskCount: taskCount,
                save:save,
                createTask: [...state.createTask,{userData:state.userData}],
            }
        }
        
        default:{
            return {
                ...state
            }
        }
    }

}

Create-task.js

import React, {useEffect, useState} from "react";
import store from "../redux/store";
import actions from "../redux/actions";
import '../styles/create-task.scss';
import {useSelector} from "react-redux";
import TaskTemplate from "./task-template";
import SaveTemplate from "./save-template";
const CreateTask=()=> {
    // const [templates, setTemplates]=useState([]);
    const onTaskCreate = () => {
        store.dispatch({type: actions.ON_CREATE_TASK, payload: {'taskCount':taskCount + 1,'save':false}})
        addTemplate();
        store.dispatch({type:actions.ON_ADD_TEMPLATES, payload:template});
    }
    const createTask = useSelector(({reducers}) => {
        const {taskCount, taskDetails,save,templates} = reducers;
        return {taskCount, taskDetails,save, templates};
    });
    const {taskCount, taskDetails,save,templates} = createTask;
    const {userData}=taskDetails;
    const globalTemplates=createTask.templates;
    let template = globalTemplates;
    const addTemplate = () => {
            template.push(<div key={`template${taskCount}`} id={`task${taskCount+1}`}><TaskTemplate/></div>);
        return template;
    }
    useEffect(()=>{
        // setTemplates(globalTemplates)
    },[])

    return (
        <div>
            <div className={"create-task"}>
                <div>TASKS <span className={"task-count"}> {taskCount} </span></div>
                <div className={"add-task-button"} onClick={onTaskCreate}>
                    <button>+</button>
                </div>
            </div>
            {templates && templates.map((template)=>template)}
            {/*{save?<SaveTemplate/>:templates.map((template)=> template)}*/}
        </div>
    )
}

export default CreateTask;

Task.js

import React, {useEffect, useState} from "react";
import store from "../redux/store";
import actions from "../redux/actions";
import DatePicker from 'react-date-picker';
import {useSelector} from "react-redux";
import TimePicker from 'react-bootstrap-time-picker';
import {wrapMapToPropsConstant} from "react-redux/lib/connect/wrapMapToProps";
const TaskTemplate=(props)=>{
    const [dateValue, dateChange] = useState(new Date());
    const [time, timeChange] = useState('10:00');
   
    const tasks = useSelector(({reducers}) => {
        const { taskDetails,edit, createTask} = reducers;
        return {taskDetails, edit, createTask};
    });
    const{edit,taskDetails,createTask}=tasks;
   
    const onFieldChange=(e)=>{
        let editingTaskId=e.target.parentNode.parentNode.getAttribute("id");
        editingTaskId=editingTaskId.split("task")[1]-1;
        createTask.map((data,index)=>{
            if(index === editingTaskId){
                createTask[editingTaskId]["userData"][e.target.name]=e.target.value;
            }
        })
    }
    const dateChangeFormat = (val) =>{
        var splitDate=val.toLocaleString('hu-HU').substr(0,12);
        splitDate=splitDate.replaceAll(" ","").replaceAll(".","-");
        return splitDate;
    }
    
    return(
        <>
                <div>
                    <label>Task Description</label>
                    <input name={"task_msg"}  defaultValue={ props.task && props.task.task_msg && props.task.task_msg } onChange={(e)=>{onFieldChange(e)}}/>
                </div>
                <div>
                <label>Date</label>
                <DatePicker
                onChange={onDateChange}
                value={props.task?props.task.original_date:dateValue}
                format={"y-MM-dd"}
                name={"task_date"}
                clearIcon={""}
                />
                </div>
                <div>
                <label>Time</label>
                <TimePicker start="10:00" end="21:00"  step={30} onChange={onTimeChange} value={props.task?props.task.task_time:time} />
                </div>
                <div>
                <label>Assign User</label>
                <input name={"assigned_user"} defaultValue={ props.task && props.task.task_msg && props.task.assigned_user} onChange={(e)=>{onFieldChange(e)}}/>
                </div>
            <div>
                <button onClick={(e)=>onFormSave(e)}> Save </button>
            </div>
        </>
    )
}

export default TaskTemplate;

Output with issue: enter image description here

1 Answers

The problem is your state.userData is the reference to the same object. And here:

createTask: [...state.createTask,{userData:state.userData}]

you're just adding it again and again to the end of your createTask array. So any change to any of those objects (which are all the same object) is immediatelly reflected everywhere. You have to shallow clone it at least. Something like:

createTask: [...state.createTask,{userData: { ...state.userData } }]
Related