简体   繁体   中英

console.log prints changed state before changing

I'm trying to rearrange div's with React/Redux via Drag&Drop and there is a strange behavoir that i cant explain. I have the following reducer (reduced version for readability)

There are 5 "console.log" around the middle of the code. When i log state or structs the chrome console will print the already rearrange version. why?

export default function reducer(
    state={
        structures: [],
        elementUniqueCounter: 0,
        hoveredElement: null,
        DnD: {
            dragContent: null,
            dragOverContent: null,
            dragContentTop: true,
            dragStructure: null,
            dragOverStructure: null,
            dragStructureTop: true,
            content: null,
            mousepositon: {}
        }
    }, action) {
    let DnD = Object.assign({}, state.DnD);
    let structs = state.structures.slice();
    switch (action.type) {
        case "STOP_DRAG_CONTENT":
            let cindex_source;
            let index_source;
            let cindex_target;
            let index_target;
            let foundTarget = false;
            let foundSource = false;

            structs.map(function (struct, index) {
                struct.content.map(function (content, cindex) {
                    if(content.id === DnD.dragOverContent.props.id) {
                        cindex_target = cindex;
                        index_target = index;
                        foundTarget = true;
                    }
                    if(content.id === DnD.dragContent.props.id) {
                        cindex_source = cindex;
                        index_source = index;
                        foundSource = true;
                    }
                });
            });
            console.log(state);
            console.log(index_source);
            console.log(cindex_source);
            console.log(index_target);
            console.log(cindex_target);
            if(index_source !== undefined && cindex_source !== undefined && index_target !== undefined && cindex_target !== undefined) {
                let copy = structs[index_source].content.slice(cindex_source, cindex_source+1)[0];
                copy.content = DnD.content;
                structs[index_source].content.splice(cindex_source, 1);
                if (DnD.dragContentTop) {
                    structs[index_target].content.splice(cindex_target+1, 0, copy);
                } else {
                    structs[index_target].content.splice(cindex_target, 0, copy);
                }
            }

            DnD = {
                dragContent: null,
                dragOverContent: null,
                dragContentTop: true,
                dragStructure: null,
                dragOverStructure: null,
                dragStructureTop: true,
                content: null,
                mousepositon: {}
            };
            return {...state, DnD: DnD, structures: structs};

    }

    return state
}

It's not that it is printing the rearranged version before it happens. It is that it is printing an object that you are mutating. By the time you look at the object in the console the mutation has already occurred.

The use of splice is mutating.

structs[index_source].content.splice(cindex_source, 1);
if (DnD.dragContentTop) {
    structs[index_target].content.splice(cindex_target+1, 0, copy);
} else {
    structs[index_target].content.splice(cindex_target, 0, copy);
}

EDIT:

The above mutation is actually mutating the nested properties of state.structures . This is happening because .slice() returns a shallow copy of the original object.

The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.

The objects in the shallow copy are just pointers to the objects in state.structures . So when you use .splice() , you mutate those referenced values.

Here is a snippet to illustrate this. Run it an look at the console.log .

 const people = [ { name: "Joe", age: "52" }, { name: "Sally", age: "48" } ]; const clonedPeople = people.slice(); console.log("people === clonedPeople: ", people === clonedPeople); console.log("people[0] === clonedPeople[0]: ", people[0] === clonedPeople[0]); const deeplyClonedPeople = JSON.parse(JSON.stringify(people)); console.log("people[0] === deeplyClonedPeople[0]: ", people[0] === deeplyClonedPeople[0]); 

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM