Redux: Мнения/примеры того, как делать упорство на бэкэнде?
Мне интересно, как люди, использующие Redux, приближаются к их постоянному усилению. В частности, вы храните "действия" в базе данных или используете только последнее известное состояние приложения?
Если вы храните действия, вы просто запрашиваете их с сервера, а затем воспроизводите их все, когда загружается данная страница? Не могли ли это привести к некоторым проблемам производительности с крупномасштабным приложением, где есть много действий?
Если вы сохраняете только "текущее состояние", как вы на самом деле сохраняете это состояние в любой момент времени, когда действия происходят на клиенте?
Есть ли у кого-нибудь примеры кода того, как они соединяют редукторы редукции с backend-хранилищем?
Я знаю, что это вопрос типа "это зависит от вашего приложения", но я просто размышляю над некоторыми идеями здесь и пытаюсь понять, как эта "безгражданная" архитектура может работать в полном стеке чувство.
Спасибо всем.
Ответы
Ответ 1
Определенно сохраняйте состояние ваших редукторов!
Если вы сохранили последовательность действий вместо этого, вы никогда не сможете изменять свои действия в своем интерфейсе, не возившись внутри своей базы данных prod.
Пример: сохранение состояния редуктора на сервере
Мы начнем с трех дополнительных типов действий:
// actions: 'SAVE', 'SAVE_SUCCESS', 'SAVE_ERROR'
Я использую redux-thunk для выполнения асинхронных вызовов сервера: это означает, что одна функция-создатель действия может dispatch
выполнять дополнительные действия и проверять текущее состояние.
Создатель действия save
немедленно отправляет одно действие (чтобы вы могли показать счетчик или отключить кнопку "сохранить" в своем пользовательском интерфейсе). Затем он отправляет SAVE_SUCCESS
или SAVE_ERROR
действия после завершения запроса POST.
var actionCreators = {
save: () => {
return (dispatch, getState) => {
var currentState = getState();
var interestingBits = extractInterestingBitsFromState(currentState);
dispatch({type: 'SAVE'});
window.fetch(someUrl, {
method: 'POST',
body: JSON.stringify(interestingBits)
})
.then(checkStatus) // from https://github.com/github/fetch#handling-http-error-statuses
.then((response) => response.json())
.then((json) => dispatch actionCreators.saveSuccess(json.someResponseValue))
.catch((error) =>
console.error(error)
dispatch actionCreators.saveError(error)
);
}
},
saveSuccess: (someResponseValue) => return {type: 'SAVE_SUCCESS', someResponseValue},
saveError: (error) => return {type: 'SAVE_ERROR', error},
// other real actions here
};
(N.B. $.ajax
будет полностью работать вместо материала window.fetch
, я просто предпочитаю не загружать весь jQuery для одной функции!)
Редуктор просто отслеживает любой выдающийся запрос сервера.
function reducer(state, action) {
switch (action.type) {
case 'SAVE':
return Object.assign {}, state, {savePending: true, saveSucceeded: null, saveError: null}
break;
case 'SAVE_SUCCESS':
return Object.assign {}, state, {savePending: false, saveSucceeded: true, saveError: false}
break;
case 'SAVE_ERROR':
return Object.assign {}, state, {savePending: false, saveSucceeded: false, saveError: true}
break;
// real actions handled here
}
}
Возможно, вам захочется что-то сделать с someResponseValue
, который вернулся с сервера - возможно, это идентификатор вновь созданного объекта и т.д. и т.д.
Надеюсь, что это поможет, это сработало до сих пор для меня!
Ответ 2
Определенно сохраняйте свои действия!
Это всего лишь контрпример, добавляющий комментарий Дэна Фитча в предыдущем ответе.
Если вы сохраните свое состояние, вы никогда не сможете изменить свое состояние без изменения столбцов и таблиц в вашей базе данных. Штат показывает вам только то, как обстоят дела сейчас, вы не можете восстановить предыдущее состояние и не будете знать, какие факты произошли.
Пример: сохранить действие на сервере
Ваше action
уже является "типом" и "полезной нагрузкой", и это, вероятно, все, что вам нужно в архитектуре Event-Driven/Event-Sourcing.
Вы можете позвонить своему бэк- actionCreator
и отправить действия внутри вашего actionCreator
(см. Ответ Дэна Фокса).
Другой альтернативой является использование промежуточного программного обеспечения для фильтрации действий, которые необходимо выполнить, и отправки их на сервер, а также, при необходимости, для отправки новых событий в ваш магазин.
const persistenceActionTypes = ['CREATE_ORDER', 'UPDATE_PROFILE'];
// notPersistenceActionTypes = ['ADD_ITEM_TO_CART', 'REMOVE_ITEM_FROM_CART', 'NAVIGATE']
const persistenceMiddleware = store => dispatch => action => {
const result = dispatch(action);
if (persistenceActionTypes.indexOf(action.type) > -1) {
// or maybe you could filter by the payload. Ex:
// if (action.timestamp) {
sendToBackend(store, action);
}
return result;
}
const sendToBackend = (store, action) => {
const interestingBits = extractInterestingBitsFromAction(action);
// déjà vu
window.fetch(someUrl, {
method: 'POST',
body: JSON.stringify(interestingBits)
})
.then(checkStatus)
.then(response => response.json())
.then(json => {
store.dispatch(actionCreators.saveSuccess(json.someResponseValue));
})
.catch(error => {
console.error(error)
store.dispatch(actionCreators.saveError(error))
});
}
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk';
createStore(
yourReducer,
aPreloadedState,
applyMiddleware(thunk, persistenceMiddleware)
)
(Вы также можете использовать промежуточное ПО для отправки текущего состояния резервной store.getState()
. Вызовите store.getState()
.)
Ваше приложение уже знает, как преобразовать действия в состояние с помощью reducers
, так что вы также можете получать действия из своего бэкэнда.