сравнить 2 массива объектов, один со старыми и один с новыми данными, затем обновить состояние в соответствии с новыми данными - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть пользователь, у которого есть данные на странице в этой форме:

[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}]

Запрос Apollo загружает эти данные. Пользователь может добавлять или удалять имена со страницы, используя форму. Мутация Apollo обрабатывает запросы на добавление или удаление. RefetchQueries вызывается после мутации, состояние обновляется и список имен перерисовывается.

Проблема в том, что если я добавлю имя, refetchQueries вернет все 4 объекта и, в свою очередь, все 4 объекта будут установлены в состояние.

[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}, { name: 'Mary', id: 4 }]

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

loadData = (names, that) => {

        that.setState({ loading:true });

        let data = {};
        data.names= [];

        const oldNames = that.state.names;

        names.map(name=> (
            data.names.push({ name: name.name, id: name.id })
        ));

       that.setState({names: data.names, loading: false });
}

Вышеупомянутая функция вызывается в componentWillUpdate следующим образом:

componentWillUpdate(nextProps, nextState) {
    loadData(nextProps.names, this);
}

Я пытаюсь изменить эту функцию следующим образом:

updateData = (names, that) => {

        let data = {};
        data.names = [];

        const oldNames = that.state.names ;

        names.map(name => (
            data.names.push({ name: name.name, id: name.id })
        ));

        let difference = _(data.names)
            .differenceBy(oldNames, 'id', 'name')
            .map(_.partial(_.pick, _, 'id', 'name'))
            .value();

        if (data.names.length > oldNames.length)
        that.setState(prevState => ({
            names: [...prevState.names, {name: difference[0].name, id: difference[0].id}]
        }))
}

Но найти разницу между старыми и новыми данными таким способом не очень приятно. Я пробовал решения из Сравните 2 массива, которые возвращают разницу , но я не смог заставить его работать. Я надеюсь, что вы можете помочь мне представить лучший способ найти разницу. В приведенном выше примере я использовал lodash, но это не обязательно. Мне также интересно, есть ли лучший способ. Например, напрямую получите результат от мутации Apollo и добавьте этот результат в State.

ОБНОВЛЕНИЕ сопоставления узлов:

render() {

        if (this.state.loading) { return <div>Loading...</div> }

        const links = this.state.links.map( (link,i) => {
            return (
                <Link
                    linkClass={this.props.linkClass}
                    key={link.target+i}
                    data={link}
                />);
        });

        const nodes = this.state.nodes.map( (node) => {
            return (
                <Node
                    nodeClass={this.props.nodeClass}
                    data={node}
                    label={node.label}
                    key={node.id}
                    onClick={this.onClickHandler.bind(this, node)}
                />);
        });

        return (
            <div className="graphContainer">
                <svg className="graph" width={FORCE.width} height={FORCE.height}>
                    <g >
                        {links}
                    </g>
                    <g >
                        {nodes}
                    </g>
                </svg>
            </div>
        );
    }
}

1 Ответ

0 голосов
/ 27 апреля 2018

Когда вы вызываете this.setState({ names: newArray }), newArray должен быть вновь созданным массивом (поскольку вы не можете напрямую изменять состояние), поэтому не имеет значения, создаете ли вы этот массив на основе различий или просто используете результат из вызова API.

Другими словами, нет никакой разницы между setState({ names: [1, 2, 3] }) или setState({ names: [...someOldState, 3] }), поскольку вы все еще устанавливаете names для вновь созданного массива в обоих случаях, поэтому ваша попытка вычисления разницы никоим образом не поможет вашему намерению .

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

Эта оптимизация выполняется на уровне виртуального DOM. Если вы хотите избежать вызова render в неизмененных компонентах Link и Node, их необходимо объявить как PureComponent или с помощью функции shouldComponentUpdate, если подпорки не мелкие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...