상태 트리의 일부를 localStorage에 유지하고 싶습니다. 적절한 장소는 무엇입니까? 감속기 또는 행동?
답변
감속기는 순수하고 부작용이 없어야하기 때문에이 작업을 수행하기에 적절한 장소는 아닙니다.
구독자에서 수행하는 것이 좋습니다.
store.subscribe(() => {
// persist your state
})
상점을 작성하기 전에 지속 된 파트를 읽으십시오.
const persistedState = // ...
const store = createStore(reducer, persistedState)
사용 combineReducers()
하면 상태를받지 못한 감속기가 기본 state
인수 값을 사용하여 정상적으로 “부팅”됩니다 . 이것은 매우 편리 할 수 있습니다.
localStorage에 너무 빨리 쓰지 않거나 구독자에게 문제를 일으키지 않으면 성능 문제가 발생하는 것이 좋습니다.
마지막으로,이를 대안으로 캡슐화하는 미들웨어를 작성할 수 있지만, 더 간단한 솔루션이기 때문에 구독자로 시작합니다.
답변
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'))
: {}
그런 다음이 persistedState
상수를 다음 createStore
과 같이 메소드에 전달 하십시오.
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
답변
한마디로 : 미들웨어.
redux-persist를 확인하십시오 . 또는 직접 작성하십시오.
[업데이트 2016. 12. 18] 현재 비활성 또는 더 이상 사용되지 않는 두 개의 유사한 프로젝트에 대한 언급을 제거하도록 편집되었습니다.
답변
위의 솔루션에 문제가있는 사람은 직접 작성할 수 있습니다. 내가 한 일을 보여 드리겠습니다. 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;
답변
@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
)
);
차이점은 우리는 단지 몇 가지 행동을 저장한다는 것입니다. 당신은 이벤트의 디 바운스 함수를 사용하여 상태의 마지막 상호 작용 만 저장할 수 있습니다
답변
조금 늦었지만 여기에 언급 된 예에 따라 지속적인 상태를 구현했습니다. X 초마다 상태를 업데이트하려는 경우이 방법이 도움이 될 수 있습니다.
-
랩퍼 함수 정의
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!") } }
-
구독자에서 랩퍼 함수 호출
store.subscribe((state) => { updateLocalStorage(store.getState()) });
이 예에서 업데이트가 얼마나 자주 트리거되는지에 관계없이 상태는 최대 5 초마다 업데이트됩니다.
답변
다른 답변 (및 Jam Creencia ‘s Medium article ) 에서 제공되는 우수한 제안과 짧은 코드 발췌를 바탕 으로 완벽한 솔루션이 있습니다!
로컬 스토리지와 상태를 저장 /로드하는 2 개의 함수가 포함 된 파일이 필요합니다.
// FILE: src/common/localStorage/localStorage.js
// Pass in Redux store's state to save it to the user's browser local storage
export const saveState = (state) =>
{
try
{
const serializedState = JSON.stringify(state);
localStorage.setItem('state', serializedState);
}
catch
{
// We'll just ignore write errors
}
};
// Loads the state and returns an object that can be provided as the
// preloadedState parameter of store.js's call to configureStore
export const loadState = () =>
{
try
{
const serializedState = localStorage.getItem('state');
if (serializedState === null)
{
return undefined;
}
return JSON.parse(serializedState);
}
catch (error)
{
return undefined;
}
};
이러한 함수는 store.js 에서 가져 와서 상점을 구성합니다.
참고 : 하나의 종속성을 추가해야합니다. npm install lodash.throttle
// FILE: src/app/redux/store.js
import { configureStore, applyMiddleware } from '@reduxjs/toolkit'
import throttle from 'lodash.throttle';
import rootReducer from "./rootReducer";
import middleware from './middleware';
import { saveState, loadState } from 'common/localStorage/localStorage';
// By providing a preloaded state (loaded from local storage), we can persist
// the state across the user's visits to the web app.
//
// READ: https://redux.js.org/recipes/configuring-your-store
const store = configureStore({
reducer: rootReducer,
middleware: middleware,
enhancer: applyMiddleware(...middleware),
preloadedState: loadState()
})
// We'll subscribe to state changes, saving the store's state to the browser's
// local storage. We'll throttle this to prevent excessive work.
store.subscribe(
throttle( () => saveState(store.getState()), 1000)
);
export default store;
상점은 index.js 로 가져 오므로 App.js 를 랩핑하는 제공자로 전달 될 수 있습니다 .
// FILE: src/index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './app/core/App'
import store from './app/redux/store';
// Provider makes the Redux store available to any nested components
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
절대 가져 오기에는 YourProjectFolder / jsconfig.json에 대한 변경이 필요합니다 . 처음에는 파일을 찾을 수없는 경우 파일을 찾을 위치를 알려줍니다. 그렇지 않으면 src 외부에서 무언가를 가져 오려고 시도하는 것에 대한 불만이 표시 됩니다.
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}