Лучший способ обновить связанные поля состояния с помощью Split reducers?
Я пытаюсь разработать идеальный способ обновления нескольких полей верхнего уровня в моем дереве состояний, сохраняя при этом разделенные редукторы.
вот простое решение, которое я придумал.
var state = {
fileOrder: [0],
files: {
0:{
id: 0,
name: 'asdf'
}
}
};
function handleAddFile(state, action) {
return {...state, ...{[action.id]:{id: action.id, name: action.name}}};
};
function addFileOrder(state, action) {
return [...state, action.id];
}
// Adding a file should create a new file, and add its id to the fileOrder array.
function addFile(state, action) {
let id = Math.max.apply(this, Object.keys(state.files)) + 1;
return {
...state,
fileOrder: addFileOrder(state.fileOrder, {id}),
files: handleAddFile(state.files, {id, name: action.name})
};
}
в настоящее время я могу отправить одно действие {type: ADD_FILE, fileName: 'x'}
, потом addFile
создает действие внутри для отправки в addFileOrder
и addFile
.
мне любопытно, считается ли это лучшим подходом для выполнения любого из приведенных ниже.
вместо отправить два действия, один, чтобы добавить файл, а затем получить его идентификатор и отправить ADD_TO_FILE_ORDER
действие с идентификатором.
Или огонь и действие, как {type: ADD_FILE, name: 'x', id: 1}
, вместо addFile
для вычисления нового идентификатора. Это позволит мне использовать combineReducers
и фильтр по типу действия.
Этот пример, вероятно, тривиален, но мое фактическое дерево состояний немного сложнее, поскольку каждый добавляемый файл также должен быть добавлен к другим сущностям.
для некоторого дополнительного контекста будет выглядеть более полное дерево состояний вроде этого.
{
"fileOrder": [0]
"entities": {
"files": {
0: {
id: 0,
name: 'hand.png'
}
},
"animations": {
0: {
id: 0,
name: "Base",
frames: [0]
}
},
"frames": {
0: {
id: 0,
duration: 500,
fileFrames: [0]
}
},
"fileFrames": {
0: {
id: 0,
file: 0,
top: 0,
left: 0,
visible: true
}
}
}
}
добавление файла необходимо:
- добавьте его в хэш файлов.
- добавьте его в массив fileOrder.
- добавить fileFrame ссылка на файл, для каждого из кадров.
- добавьте каждый новый файловый фрейм в фрейм, для которого он был создан.
последние два момента заставляют меня задуматься, смогу ли я вообще использовать combineReducers.
2 ответов
Я нашел довольно простое решение этой проблемы.
оба этих блока из документации функционально одинаковы.
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
});
// This is functionally equivalent.
function reducer(state, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
};
}
Я закончил настройку второго блока и всегда проходил по моему глобальному дереву состояний. Пока ничто не изменяет состояние по пути, все редукторы работают нормально.
// Simple change to pass the entire state to each reducer.
// You have to be extra careful to keep state immutable here.
function reducer(state, action) {
return {
a: doSomethingWithA(state.a, action, state),
b: processB(state.b, action, state),
c: c(state.c, action, state)
};
}
опираясь на авторское решение:
У меня была такая же проблема, где мне нужен (немного) доступ за пределами части моего редуктора государства. Я думаю, что это решение может работать на практике, если вы старательно не меняете ничего, кроме одного значения, такого как флаг или счетчик.
это нечистота может быстро сойти с ума, если другие разработчики не были так защищены своим кодом. Представьте, что произойдет, если a начнет изменять B и c часть состояние, B изменение части a и c и так далее.
вы можете рассмотреть возможность сокращения площади поверхности примеси следующим образом:
function reducer(state, action) {
return {
a: doSomethingWithA(state.a, action, state.globals),
b: processB(state.b, action, state.globals),
c: c(state.c, action, state.globals)
};
}