ReactJS - переменные состояния действуют странно - PullRequest
1 голос
/ 31 января 2020

Я недавно начал использовать 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;
}

Ответы [ 3 ]

0 голосов
/ 01 февраля 2020

Я думаю, что это работает так, как вы ожидаете, но консоль проверяет значение после его изменения.

Если bubbleSort() изменяет ваши данные на месте, а не возвращает новую нетронутую копию с внесенными вами изменениями , тогда ваша консоль просто удерживает ссылку на объект, а затем показывает ее текущие значения при проверке.

Это одна из причин, и есть много других причин, по которым вы хотите обрабатывать состояние неизменно , Никогда не меняйте объекты в состоянии. Всегда предоставляйте новые объекты в состоянии.

Могу поспорить, что это решит вашу проблему:

bubbleSort([...members]);

Но вам, вероятно, следует реализовать пузырьковую сортировку, чтобы вернуть новый массив или объект, а не изменять существующий один.

Без источника bubbleSort Не могу точно сказать, что это правильно. Но я видел такое поведение раньше, и это было причиной.

0 голосов
/ 04 февраля 2020

Оказывается, что проблема не имела никакого отношения к управлению React State, вся проблема была связана с тем, как я обрабатывал массивы в своей функции bubbleSort. Мне нужно было использовать оператор распространения, чтобы последующие операции с массивами не влияли на исходный массив. Спасибо за всю предоставленную информацию!

0 голосов
/ 01 февраля 2020

ОК, поэтому я не до конца понимаю проблему, но похоже, что вы хотите, чтобы одна функция завершила sh, что она должна делать до запуска следующей функции.

  async bSort() {
    await this.setState(
      state => {
        console.log("PRE BSORT STATE", state);
        let members = state.members;
        let states = bubbleSort(members);
        return { states: states, animate: true };
      },
      () => this.animate()
    );
  }
...