web-dev-qa-db-ja.com

ReduxアプリのlocalStorageに書き込む場所

状態ツリーの一部をlocalStorageに永続化したいのですが。適切な場所は何ですか?減力剤か行為か。

134
Marco de Jongh

還元剤は純粋で副作用がないため、これを行うのに適した場所ではありません。

私はただ加入者でそれをすることをお勧めします:

store.subscribe(() => {
  // persist your state
})

ストアを作成する前に、これらの持続部分を読んでください。

const persistedState = // ...
const store = createStore(reducer, persistedState)

combineReducers()を使用すると、状態を受け取らなかったリデューサーはデフォルトのstate引数値を使用して通常どおり「起動」することに気付くでしょう。これはかなり便利です。

LocalStorageへの書き込みが速すぎないように、またはパフォーマンスに問題があるように、サブスクライバをデバウンスすることをお勧めします。

最後に、それをカプセル化したミドルウェアを代替手段として作成することもできますが、私は加入者から始めることにしました。なぜなら、それはより単純なソリューションであり、うまく機能するからです。

179
Dan Abramov

Dan Abramovの答えの空白を埋めるには、store.subscribe()を次のように使うことができます。

store.subscribe(()=>{
  localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})

ストアを作成する前に、localStorageを確認して、キーの下にあるJSONを次のように解析します。

const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : {}

次に、このperistedStateメソッドを次のようにcreateStoreメソッドに渡します。

const store = createStore(
  reducer, 
  persistedState,
  /* any middleware... */
)
126

一言で言えば:ミドルウェア。

チェックアウト redux-persist 。または自分で書いてください。

[2016年12月18日更新] 2つの類似したプロジェクトが非アクティブまたは非推奨になったという言及を削除するように編集しました。

42
David L. Walsh

誰かが上記の解決策で何か問題を抱えているならば、あなたはあなた自身に書くことができます。私がしたことをお見せしましょう。 saga middlewareを無視するということは、localStorageMiddlewarereHydrateStoreという2つの方法に焦点を絞るだけです。 localStorageMiddlewareはすべてのredux stateをプルしてlocal storageに入れ、rehydrateStoreはローカルストレージにある場合はすべてのapplicationStateをプルしてredux storeに入れる

import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga';
import decoristReducers from '../reducers/decorist_reducer'

import sagas from '../sagas/sagas';

const sagaMiddleware = createSagaMiddleware();

/**
 * Add all the state in local storage
 * @param getState
 * @returns {function(*): function(*=)}
 */
const localStorageMiddleware = ({getState}) => { // <--- FOCUS HERE
    return (next) => (action) => {
        const result = next(action);
        localStorage.setItem('applicationState', JSON.stringify(
            getState()
        ));
        return result;
    };
};


const reHydrateStore = () => { // <-- FOCUS HERE

    if (localStorage.getItem('applicationState') !== null) {
        return JSON.parse(localStorage.getItem('applicationState')) // re-hydrate the store

    }
}


const store = createStore(
    decoristReducers,
    reHydrateStore(),// <-- FOCUS HERE
    applyMiddleware(
        sagaMiddleware,
        localStorageMiddleware,// <-- FOCUS HERE 
    )
)

sagaMiddleware.run(sagas);

export default store;
7
Gardezi

私は@Gardeziに答えることはできませんが、彼のコードに基づく選択肢は次のようになります。

const rootReducer = combineReducers({
    users: authReducer,
});

const localStorageMiddleware = ({ getState }) => {
    return next => action => {
        const result = next(action);
        if ([ ACTIONS.LOGIN ].includes(result.type)) {
            localStorage.setItem(appConstants.APP_STATE, JSON.stringify(getState()))
        }
        return result;
    };
};

const reHydrateStore = () => {
    const data = localStorage.getItem(appConstants.APP_STATE);
    if (data) {
        return JSON.parse(data);
    }
    return undefined;
};

return createStore(
    rootReducer,
    reHydrateStore(),
    applyMiddleware(
        thunk,
        localStorageMiddleware
    )
);

違いは、アクションを保存しているだけなので、デバウンス関数を使用して自分の状態の最後のインタラクションのみを保存することができます。

3
Douglas Caina

少し遅れましたが、ここで説明する例に従って永続的な状態を実装しました。 X秒ごとにのみ状態を更新する場合、このアプローチは次の場合に役立ちます。

  1. ラッパー関数を定義する

    let oldTimeStamp = (Date.now()).valueOf()
    const millisecondsBetween = 5000 // Each X milliseconds
    function updateLocalStorage(newState)
    {
        if(((Date.now()).valueOf() - oldTimeStamp) > millisecondsBetween)
        {
            saveStateToLocalStorage(newState)
            oldTimeStamp = (Date.now()).valueOf()
            console.log("Updated!")
        }
    }
    
  2. サブスクライバーでラッパー関数を呼び出す

        store.subscribe((state) =>
        {
        updateLocalStorage(store.getState())
         });
    

この例では、更新がトリガーされる頻度に関係なく、状態は最大 5秒ごとに更新されます。

1
movcmpret