Вопрос по javascript, redux, state, local-storage – Куда писать в localStorage в приложении Redux?

124

Я хочу сохранить некоторые части моего дерева состояний в localStorage. Какое уместное место для этого? Редуктор или действие?

Ваш Ответ

5   ответов
1

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
    )
);

разница в том, что мы просто сохраняем некоторые действия, вы можете использовать функцию debounce для сохранения только последнего взаимодействия вашего состояния

7

вы можете написать свое. Позвольте мне показать вам, что я сделал. игнорироватьsaga middleware вещи просто сосредоточены на двух вещахlocalStorageMiddleware а такжеreHydrateStore метод.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;
Привет, не приведет ли это к большому количеству записей вlocalStorage даже когда ничего в магазине не изменилось? Как вы компенсируете ненужные записи user566245
168

потому что редукторы должны быть чистыми и не иметь побочных эффектов.

Я бы порекомендовал просто сделать это в подписчике:

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

Перед созданием магазина прочитайте эти сохраненные части:

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

Если вы используетеcombineReducers() вы заметите, что редукторы, которые не получили состояние, будут «загружаться» как обычно, используя их значения по умолчаниюstate значение аргумента. Это может быть очень удобно.

Желательно, чтобы вы отказались от подписчика, чтобы не писать слишком быстро в localStorage, иначе у вас возникнут проблемы с производительностью.

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

в обратном вызове store.subscribe у вас есть полный доступ к текущим данным магазина, поэтому вы можете сохранить любую интересующую вас часть Bo Chen
Изменить: На самом деле, я смотрел ваше видео, и я думаю, что регулирование подписки помогает Stephen Paul
Что делать, если я хотел бы подписаться только на часть государства? это возможно? Я пошел дальше с чем-то немного другим: 1. сохранить сохраненное состояние за пределами редукса. 2. загрузить сохраненное состояние внутри реактора-конструктора (или с помощью componentWillMount) с редукционным действием. 2 вполне нормально вместо прямой загрузки сохраненных данных в хранилище? (который я пытаюсь сохранить отдельно для ССР). Кстати, спасибо за Redux! Это круто, мне это нравится, после того, как я заблудился с моим большим проектом, теперь все стало простым и предсказуемым :) Mark Uretsky
Существуют ли законные проблемы с производительностью при сериализации состояния при каждом обновлении магазина? Может ли браузер сериализоваться в отдельном потоке? Stephen Paul
40

Проверять, выписыватьсяперевождь-упорствовать, Или написать свой.

[ОБНОВЛЕНИЕ 18 декабря 2016 года] Отредактировано, чтобы удалить упоминание о двух похожих проектах, которые сейчас неактивны или устарели.

119

Для заполнения пробелов ответа Дана Абрамова вы можете использовать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... */
)
создание промежуточного программного обеспечения может выглядеть немного лучше, но я согласен, что это эффективно и достаточно для большинства случаев Bo Chen
@AndrewSamuelsen Я получаю эту ошибку. Можете ли вы сказать мне, что я скучаюTypeError: Cannot read property 'subscribe' of undefined Gardezi
Мне нужно было поменятьpersistedState от{} вundefined в троичном, чтобы нормально работать. Damjan Pavlica
Просто и эффективно, без лишних зависимостей. AxeEffect

Похожие вопросы