Eyalet ağacımın bazı kısımlarını localStorage'a devam ettirmek istiyorum. Bunun için uygun yer neresi? Düşürücü mü, eylem mi?
Eyalet ağacımın bazı kısımlarını localStorage'a devam ettirmek istiyorum. Bunun için uygun yer neresi? Düşürücü mü, eylem mi?
Yanıtlar:
Redüktör bunu yapmak için asla uygun bir yer değildir çünkü redüktörler saf olmalı ve yan etkisi olmamalıdır.
Ben sadece bir abone yapmak tavsiye ederim:
store.subscribe(() => {
// persist your state
})
Mağazayı oluşturmadan önce, bu kalıcı bölümleri okuyun:
const persistedState = // ...
const store = createStore(reducer, persistedState)
Eğer kullanırsanız combineReducers()
normal olarak varsayılan kullanarak “yukarı önyükleme” olacak devlet almadıklarını düşürücüler fark edeceksiniz state
argüman değerini. Bu oldukça kullanışlı olabilir.
LocalStorage'a çok hızlı yazmamanız için abonenizi geri almanız veya performans sorunlarınız olması önerilir.
Son olarak, alternatif olarak kapsülleyen bir ara katman yazılımı oluşturabilirsiniz, ancak daha basit bir çözüm olduğu ve işi iyi yaptığı için bir abone ile başlayacağım.
Dan Abramov'un cevabının boşluklarını doldurmak için şöyle kullanabilirsiniz store.subscribe()
:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
Mağazayı oluşturmadan önce localStorage
, anahtarınızın altındaki herhangi bir JSON'u aşağıdaki gibi kontrol edin ve ayrıştırın:
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
Daha sonra bu persistedState
sabiti createStore
yönteminize şu şekilde aktarırsınız :
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
persistedState
dönmeli initialState
mi? Aksi takdirde createStore
boş nesne ile başlayacağını düşünüyorum .
Tek kelimeyle: ara katman yazılımı.
Redux-persist'u kontrol edin . Veya kendiniz yazın.
[UPDATE 18 Ara 2016] Şu anda etkin olmayan veya kullanımdan kaldırılan benzer iki projeden bahsetmek için düzenlendi.
Yukarıdaki çözümlerle ilgili herhangi bir sorun varsa, kendinize yazabilirsiniz. Size ne yaptığımı göstereyim. saga middleware
Şeyleri görmezden gel, sadece iki şeye localStorageMiddleware
ve reHydrateStore
yönteme odaklan . localStorageMiddleware
çekme hepsi redux state
ve koyar onu local storage
ve rehydrateStore
tüm çekme applicationState
yerel deposunda eğer mevcut ve koyar onu içinderedux 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
, mağazadaki hiçbir şey değişmediğinde bile çok fazla yazımla sonuçlanmaz mı? Gereksiz yazmaları nasıl telafi edersiniz
@Gardezi cevap veremem ama koduna dayalı bir seçenek olabilir:
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
)
);
fark şu ki, sadece bazı eylemleri kaydediyoruz, olayınızın yalnızca son durumunuzun etkileşimini kaydetmek için bir geri dönme işlevi kullanabilirsiniz.
Biraz geç kaldım ama burada belirtilen örneklere göre kalıcı bir durum uyguladım. Durumu yalnızca her X saniyede bir güncellemek istiyorsanız, bu yaklaşım size yardımcı olabilir:
Sarıcı işlevini tanımlama
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!")
}
}
Abonenizdeki bir sarma işlevini çağırın
store.subscribe((state) =>
{
updateLocalStorage(store.getState())
});
Bu örnekte, güncellemenin ne sıklıkta tetiklendiğine bakılmaksızın , durum en fazla her 5 saniyede bir güncellenir.
(state) => { updateLocalStorage(store.getState()) }
de lodash.throttle
böyle: store.subscribe(throttle(() => {(state) => { updateLocalStorage(store.getState())} }
ve mantık içini kontrol süresini kaldırın.
Diğer yanıtlarda (ve Jam Creencia'nın Medium makalesinde ) sağlanan mükemmel öneriler ve kısa kod alıntıları üzerine, tam bir çözüm!
Durumu yerel depolama birimine kaydeden / yerel depolama biriminden yükleyen 2 işlev içeren bir dosyaya ihtiyacımız var:
// 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;
}
};
Bu işlevler mağazamızı yapılandırdığımız store.js tarafından içe aktarılır :
NOT: Bir bağımlılık eklemeniz gerekir: 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;
Mağaza index.js'ye aktarılır, böylece App.js'yi saran Sağlayıcıya aktarılabilir :
// 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')
)
Mutlak içe aktarma işlemlerinin YourProjectFolder / jsconfig.json için bu değişikliği gerektirdiğini unutmayın . Aksi takdirde, src dışından bir şey içe aktarmaya çalışmayla ilgili şikayetler görürsünüz .
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}