首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Redux、归一化实体和lodash合并

Redux、归一化实体和lodash合并
EN

Stack Overflow用户
提问于 2017-01-26 19:02:59
回答 2查看 1.7K关注 0票数 2

我正在使用Redux、React和Lodash以及一个相当标准的规范化实体存储。

当我在redux reducer中合并新的实体时,对所有现有实体的引用都会改变(尽管没有被修改),导致任何纯组件重新呈现。

有没有一种方法可以替代lodash的merge,既可以合并,又可以保持对不在被合并的对象中的值的现有引用?

代码语言:javascript
复制
let entities = { 
  [1]: {a: true },
  [2]: {a: true, b: true },
}
let response = { 
  [2]: {a: false }
}
let newEntities = _.merge({}, entities, response)

console.log(entities[1] === newEntities[1]) // false

我不能在这里使用Object.assign/ES6 Spread,因为newEntities[2].b将被删除。

我确实意识到还有其他的解决方案,比如自定义sCU和重新选择,然而,在reducer级别处理这一点要干净得多,而不是必须修改每个在其道具上进行相等引用检查的组件。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-26 19:18:17

mergeWith与定制器一起使用:

代码语言:javascript
复制
let keepRef = (objValue, srcValue) => (
  objValue === undefined ? srcValue : _.mergeWith({}, objValue, srcValue, keepRef)
)
let newEntities = _.mergeWith({}, entities, response, keepRef)
票数 1
EN

Stack Overflow用户

发布于 2018-03-23 04:28:19

我详述了@Pavlo的精彩答案。我添加了对数组和集合的支持。我将集合定义为对象的数组,其中每个对象都有一个id键。这在react/redux和标准化数据中非常常见。

代码语言:javascript
复制
import { mergeWith, isPlainObject, isEmpty, keyBy } from 'lodash'

// https://stackoverflow.com/a/49437903/1828637
// mergeWith customizer.
// by default mergeWith keeps refs to everything,
// this customizer makes it so that ref is only kept if unchanged
// and a shallow copy is made if changed. this shallow copy continues deeply.
// supports arrays of collections (by id).
function keepUnchangedRefsOnly(objValue, srcValue) {
    if (objValue === undefined) { // do i need this?
        return srcValue;
    } else if (srcValue === undefined) { // do i need this?
        return objValue;
    } else if (isPlainObject(objValue)) {
        return mergeWith({}, objValue, srcValue, keepUnchangedRefsOnly);
    } else if (Array.isArray(objValue)) {
        if (isEmpty(objValue) && !isEmpty(srcValue))return [...srcValue];
        else if (!isEmpty(objValue) && isEmpty(srcValue)) return objValue;
        else if (isEmpty(objValue) && isEmpty(srcValue)) return objValue; // both empty
        else {
            // if array is array of objects, then assume each object has id, and merge based on id
            // so create new array, based objValue. id should match in each spot

            if (isPlainObject(objValue[0]) && objValue[0].hasOwnProperty('id')) {
                const srcCollection = keyBy(srcValue, 'id');

                const aligned = objValue.map(el => {
                    const { id } = el;
                    if (srcCollection.hasOwnProperty(id)) {
                        const srcEl = srcCollection[id];
                        delete srcCollection[id];
                        return mergeWith({}, el, srcEl, keepUnchangedRefsOnly);
                    } else {
                        return el;
                    }
                });

                aligned.push(...Object.values(srcCollection));

                return aligned;
            } else {
                return [ ...objValue, ...srcValue ];
            }
        }
    }
}

用法:

代码语言:javascript
复制
const state = {
    chars: ['a', 'b'],
    messages: [
        {
            id: 1,
            text: 'one'
        },
        {
            id: 2,
            text: 'ref to this entry will be unchanged'
        }
    ]
}

const response = {
    chars: ['c', 'd'],
    messages: [
        {
            id: 1,
            text: 'changed ref text one'
        },
        {
            id: 3,
            text: 'three'
        }
    ]
}

const stateNext = mergeWith({}, state, response, keepUnchangedRefsOnly)

生成的stateNext为:

代码语言:javascript
复制
{
    chars: [
        'a',
        'b',
        'c',
        'd'
    ],
    messages: [
        {
            id: 1,
            text: 'changed ref text one'
        },
        {
            'id': 2,
            text: 'ref to this entry will be unchanged'
        },
        {
            'id': 3,
            text: 'three'
        }
    ]
}

如果你想保留undefined的值,那么用assignWith替换定制器中的mergeWith和你的用例。示例- https://stackoverflow.com/a/49455981/1828637

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41872065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档