Как я должен глубоко дублировать данные состояния в Redux?

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

Состояние нормализовано:

questionsById: {
  q01: {
    ...
    answers: ["a01"],
    ...
  }
}
answersById: {
  a01: {...}
}

При отправке действия QUESTION_DUPLICATE я также хотел бы дублировать любые ответы. В настоящее время мой создатель действия QUESTION_DUPLICATE также создает сопоставленный список новых ключей ответов, а затем редуктор ответов использует его.

Этот шаблон кажется мне громоздким, особенно если учесть возможность более глубокого дублирования (например, дублирование страницы, содержащей вопросы, содержащие ответы...). Есть ли лучший шаблон для глубокого дублирования нормализованных данных?

2 ответа

Решение

Ответ может вращаться вокруг того, как вы обычно справляетесь с нормализацией и денормализацией ваших данных. Например, в своем посте блога Practical Redux, часть 8: Управление черновиком данных формы, я повторно использую свою существующую логику нормализации (которая использует библиотеку redux-orm), чтобы скопировать элемент для редактирования между "текущим" и "черновым" срезами в моем состоянии. Таким образом, аналогичным образом, один из подходов заключается в денормализации вопроса, который вы хотите продублировать, и затем его повторной нормализации (либо в создателе действий, либо в редукторе, как вы считаете нужным).

Я остановился на использовании нормализатора и придумал функцию рекурсивного дубликатора. Он принимает сущность, схему и функцию keygen и рекурсивно обновляет любые вложенные сущности на основе схем, давая им новые идентификаторы. В базовом случае (когда больше нет вложенных сущностей) он вернет базовую вещь с обновленным ключом.

const duplicator = (entity, schema, keygen) => {
    const newEntity = {
            ...entity,
            [schema._idAttribute]: keygen(entity, schema)
    };
    if (Object.keys(schema.schema).length === 0) {
            return newEntity;
    }
    return Object.keys(schema.schema).reduce(
            (acc, nestedKey) => {
                    if (!entity.hasOwnProperty(nestedKey)) {
                            return acc;
                    }
                    if (!Array.isArray(schema.schema[nestedKey])) {
                            return {
                                    ...acc,
                                    [nestedKey]: duplicator(
                                            entity[nestedKey],
                                            schema.schema[nestedKey],
                                            keygen
                                    )
                            };
                    }
                    return {
                            ...acc,
                            [nestedKey]: acc[nestedKey].map((nestedEntity, index) =>
                                    duplicator(nestedEntity, schema.schema[nestedKey][0], keygen)
                            )
                    };
            },
            { ...newEntity }
    );
};

export default duplicator;

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

Другие вопросы по тегам