首页 > 解决方案 > ReactJS - 状态变量行为异常

问题描述

我最近开始使用 React,遇到了一个看似与状态变量相关的问题。

    bSort(){

        this.setState(
            state => {
                console.log("PRE BSORT STATE", state)
                let current_members = [...state.members];
                console.log("members pre BSORT", current_members);
                const updated_states = bubbleSort([...current_members]);
                return {states: updated_states, animate : true};
            },
            () => this.animate()
          );
    }

在这里,我尝试使用从函数 bubbleSort 返回的信息来更新我的状态。问题是bubbleSort的结果很奇怪:我期待一个数组数组,其中每个单独的数组代表排序进行时列表的快照。理想情况下,我会将这些快照中的每一个用作动画的帧,但实际上返回的数组由排序的最终结果的多个副本组成。这很奇怪,特别是因为我在排序过程中明确尝试保存原始步骤和中间步骤。请参阅底部的 bubbleSort() 代码。

我知道这里有很多文字,但我非常感谢帮助理解正在发生的事情,我不知所措。谢谢!

编辑:

我正在添加 bubbleSort() 的代码,以便提供更多信息。

export default function bubbleSort(list){
    let members = [...list];
    let frames= [];
    //the original order of the members should be the first frame in the list
    frames.push(members);

    let early_exit = false;
    let wall = members.length;

    while(!early_exit){

        console.log("FRAMES WITHIN BSORT", frames);

        let last_change_index = null;
        for(var i = 0; i < wall; i++){
            if(members[i+1] != null){

                console.log("COMPARING", members[i].props.style.height, "AND", members[i+1].props.style.height);

                //Here we color red the two elements that will be compared
                var new_1 = React.cloneElement(
                    members[i],
                    {
                        style : {backgroundColor : "red", height : members[i].props.style.height}
                    }
                );
                var new_2 = React.cloneElement(
                    members[i+1],
                    {
                        style : {backgroundColor : "red", height : members[i+1].props.style.height}
                    }
                );
                members[i] = new_1;
                members[i+1] = new_2;

                //and add this new comparison state to the list of frames
                frames.push(members);

                //now we decide if we need to swap the elements
                if(members[i].props.style.height > members[i+1].props.style.height){

                    console.log("SWAPPING", i, i+1);
                    //If should swap, the two elements are colored yellow and shifted on the x axis
                    let new_1_yellow = React.cloneElement(
                        new_1,
                        {
                            animate : {x : 3},
                            style : {backgroundColor : "yellow", height : new_1.props.style.height}
                        }
                    );
                    let new_2_yellow = React.cloneElement(
                        new_2,
                        {
                            animate : {x : -3},
                            style : {backgroundColor : "yellow", height : new_2.props.style.height}
                        }
                    );

                    members[i+1] = new_1_yellow;
                    members[i] = new_2_yellow;

                    last_change_index = i;

                    frames.push(members);

                    //We change the yellow swapped members back to blue
                    let new_1_blue = React.cloneElement(
                        new_1_yellow,
                        {
                            animate : {x : 0},
                            style : {backgroundColor : "blue", height : new_1_yellow.props.style.height}
                        }
                    );

                    let new_2_blue = React.cloneElement(
                        new_2_yellow,
                        {
                            animate : {x : 0},
                            style : {backgroundColor : "blue", height : new_2_yellow.props.style.height}
                        }
                    );

                    members[i+1] = new_1_blue;
                    members[i] = new_2_blue;

                    //and add this return to blue state to the list
                    frames.push(members);

                }
                else{
                //Here we re-color blue the two elements that were compared
                    let new_1_blue = React.cloneElement(
                        new_1,
                        {
                            style : {backgroundColor : "blue", height : new_1.props.style.height}
                        }
                    );
                    let new_2_blue = React.cloneElement(
                        new_2,
                        {
                            style : {backgroundColor : "blue", height : new_2.props.style.height}
                        }
                    );
                    members[i] = new_1_blue;
                    members[i+1] = new_2_blue;

                    //and add this return to blue state to the list
                    frames.push(members);
                }
            }
        }
        if(last_change_index == null){
            early_exit = true;
        }
        wall = last_change_index;
    }
    return frames;
}

标签: javascriptreactjsstate

解决方案


我认为它的工作方式与您期望的一样,但是控制台会在更改后检查该值。

如果bubbleSort()在适当的位置改变您的数据,而不是返回一个新的原始副本并进行编辑,那么您的控制台只是保留一个对象引用,然后在您检查它时显示它的当前值。

这是您希望不可变地对待状态的原因之一,还有许多其他原因。永远不要改变状态中的对象。始终提供状态中的新对象。

我打赌这会解决你的问题:

bubbleSort([...members]);

但是您可能应该实现冒泡排序以返回一个新的数组或对象,而不是修改现有的。

没有来源bubbleSort我不能肯定这是正确的。但我以前见过这种行为,这就是原因。


推荐阅读