Reduxを使用している人々がバックエンドの永続性にどのように近づいているのか疑問に思っています。特に、データベースに「アクション」を保存していますか、それともアプリケーションの最後の既知の状態のみを保存していますか?
アクションを保存している場合、サーバーにアクションを要求し、特定のページがロードされたときにそれらすべてを再生するだけですか?これにより、多くのアクションがある大規模アプリでパフォーマンスの問題が発生することはありませんか?
「現在の状態」のみを保存している場合、クライアントでアクションが発生したときに、この状態をいつでも実際に永続化していますか?
誰もがreduxリデューサーをバックエンドストレージAPIに接続する方法のコード例を持っていますか?
これは非常に「アプリに依存する」タイプの質問であることは知っていますが、ここでいくつかのアイデアを熟考し、この種の「ステートレス」アーキテクチャがフルスタックの意味でどのように機能するかを感じています。
みんな、ありがとう。
リデューサーの状態を完全に永続化する!
代わりに一連のアクションを永続化した場合、prodデータベース内をいじることなく、フロントエンドでアクションを変更することはできません。
例:1つの減速機の状態をサーバーに永続化する
3つの追加のアクションタイプから始めます。
// actions: 'SAVE', 'SAVE_SUCCESS', 'SAVE_ERROR'
redux-thunk を使用して非同期サーバー呼び出しを行います。つまり、1つのアクションクリエーター関数がdispatch
追加アクションを実行し、現在の状態を検査できることを意味します。
save
アクション作成者はすぐに1つのアクションをディスパッチします(スピナーを表示したり、UIで「保存」ボタンを無効にしたりできるように)。その後、POSTリクエストが終了すると、SAVE_SUCCESS
またはSAVE_ERROR
アクションをディスパッチします。
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
の代わりに完全に機能します。1つの関数に対して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
で何かをしたいと思うでしょう-おそらく、新しく作成されたエンティティなどのidでしょう。
これが役に立てば幸いです。これまでのところ私にとってはうまく機能しています!
アクションを完全に永続化する!
これは反例であり、前の回答のダン・フィッチの コメント に追加されています。
状態を保持した場合、データベースの列とテーブルを変更せずに状態を変更することはできません。状態は、現在の状態のみを示し、以前の状態を再構築することはできません。また、どの事実が発生したのかもわかりません。
例:サーバーにアクションを永続化する
action
はすでに「タイプ」と「ペイロード」であり、おそらくイベント駆動型/イベントソーシングアーキテクチャで必要なのはこれだけです。
バックエンドを呼び出して、actionCreator
内でアクションを送信できます(Dan Foxの answer を参照)。
別の代替手段は、 ミドルウェア を使用して、永続化する必要があるアクションをフィルタリングし、バックエンドに送信することです。オプションで、新しいイベントをストアにディスパッチします。
_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)
)
_
(ミドルウェアを使用して、現在の状態をbackedに送信することもできます。store.getState()
を呼び出します。)
アプリは reducers
でアクションを状態に変換する方法をすでに知っているので、バックエンドからアクションを取得することもできます。