ReactJS - просмотр без повторной обработки после обновления состояния с использованием среза

LK Phuc Nguyen спросил: 28 апреля 2018 в 09:25 в: reactjs

Это мой класс Content, который отображается внутри App.js. Я прочитал учебник ReactJS и понял, что мне нужно изменить данные без мутации.

https://reactjs.org/tutorial/tutorial.html

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

Этот класс управляет колодой карт, как показано ниже:

//omitted imports
import main_deck from ...
import side_deck from ...export default class Content extends Component {
    constructor(props) {
        super(props);
        this.moveToMainDeck = this.moveToMainDeck.bind(this);
        this.state = {
            mainDeck : main_deck,
            sideDeck : side_deck
        }
    }    moveToMainDeck(card) {
        const fromDeck = this.state.sideDeck.slice(); //copy the state data
        const toDeck = this.state.mainDeck.slice();        var movable = checkMovability(fromDeck, toDeck, card);
        if (movable[0] === 1) { //use slice instead of splice
            var newMain = toDeck.slice(0, movable[1]).concat([card]).concat(toDeck.slice(movable[1]));            var cardIndexInSideDeck = fromDeck.indexOf(card);
            var newSide = fromDeck.slice(0, cardIndexInSideDeck).concat(fromDeck.slice(cardIndexInSideDeck + 1));            this.setState({ mainDeck : newMain, sideDeck : newSide });
        }
        else if (movable[0] === -1)
            alert("Unable to move. Main Deck is full.");
        else //movable[0] === 0
            alert("Unable to move. Limit reached for this card in Main Deck.");
    }    render() {
        return (
            <div><MainDeck ... /><SideDeck ... /></div>
        );
    }
}

С приведенный выше код, я проверяю данные состояния, распечатывая массив JSON, состояние меняет после slice, но представление все еще не перерисовывается.

Однако, я тестировал заменив this.setState на slice(), все будет повторно отображаться после изменений состояния, например: push() или fromDeck.push(card);

Кто-нибудь скажет, что не так с toDeck.push(card);, который я использую. Большое спасибо!

2 ответа

Есть решение
César Landesa ответил: 28 апреля 2018 в 10:48

Вы можете попробовать использовать как предложено здесь :

const fromDeck = JSON.parse(JSON.stringify(this.state.sideDeck))

Это должно создать совершенно новую копию.

LK Phuc Nguyen ответил: 28 апреля 2018 в 05:00
В моем случае это не сработает, поскольку комментарий к этому предложению говорит, что он работает только в том случае, если массив содержит только примитивы, а не null или infinite. Мои данные json имеют null и не примитивные объекты. Спасибо за вашу помощь.
César Landesa ответил: 29 апреля 2018 в 06:29
В этом случае я, вероятно, использовал бы cloneDeep из lodash, так что мне не нужно было самостоятельно выполнять пользовательскую функцию.
LK Phuc Nguyen ответил: 29 апреля 2018 в 10:37
Спасибо вам большое! Наконец, он работает с lodash
Mukesh Kumar ответил: 28 апреля 2018 в 10:13

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

//Examplevar one=[{'a':'first'},{'b':'second'}]
var two=one.slice()
var three=two.slice(0,1)
three[0].a='third'//Now in all variables (one,two,three) a will have value of 'three'
LK Phuc Nguyen ответил: 28 апреля 2018 в 10:33
Я получаю то, что вы говорите, но в коде я фактически не изменяю "fromDeck" и "toDeck". Вместо этого я объявляю 2 новых vars для хранения обновленных данных. После "setState" я распечатываю данные Json для сравнения, он изменяется, но просмотр не обновляется. Вы можете предложить клонировать данные для совершенно нового адреса в javascript?