ฉันต้องการคงบางส่วนของแผนผังสถานะของฉันไปยัง localStorage สถานที่ที่เหมาะสมที่จะทำคืออะไร? ลดหรือการกระทำ?
ฉันต้องการคงบางส่วนของแผนผังสถานะของฉันไปยัง localStorage สถานที่ที่เหมาะสมที่จะทำคืออะไร? ลดหรือการกระทำ?
คำตอบ:
ตัวลดไม่เคยเป็นสถานที่ที่เหมาะสมในการทำเช่นนี้เพราะตัวลดควรบริสุทธิ์และไม่มีผลข้างเคียง
ฉันอยากจะแนะนำให้ทำในสมาชิก:
store.subscribe(() => {
// persist your state
})
ก่อนที่จะสร้างร้านค้าอ่านส่วนที่ยังคงมีอยู่:
const persistedState = // ...
const store = createStore(reducer, persistedState)
หากคุณใช้combineReducers()
คุณจะสังเกตเห็นว่าตัวลดที่ไม่ได้รับสถานะจะ“ บู๊ต” ตามปกติโดยใช้ค่าstate
อาร์กิวเมนต์เริ่มต้น มันมีประโยชน์ทีเดียว
ขอแนะนำให้คุณ debounce สมาชิกของคุณเพื่อที่คุณจะได้ไม่เขียนไปยัง 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... */
)
persistedState
ส่งคืนinitialState
แทนที่จะเป็นวัตถุเปล่า? มิฉะนั้นฉันคิดว่าcreateStore
จะเริ่มต้นด้วยวัตถุที่ว่างเปล่า
หากใครมีปัญหากับวิธีแก้ไขปัญหาข้างต้นคุณสามารถเขียนของคุณเองเพื่อ ให้ฉันแสดงสิ่งที่ฉันทำ ไม่สนใจ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
แม้ว่าจะไม่มีการเปลี่ยนแปลงอะไรในสโตร์ คุณชดเชยการเขียนที่ไม่จำเป็นได้อย่างไร
ฉันไม่สามารถตอบ @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
)
);
ความแตกต่างคือเราเพิ่งบันทึกการกระทำบางอย่างคุณสามารถใช้ฟังก์ชัน debounce เพื่อบันทึกการโต้ตอบล่าสุดของสถานะของคุณเท่านั้น
ฉันช้าไปหน่อย แต่ฉันได้ติดตั้งสถานะถาวรตามตัวอย่างที่ระบุไว้ที่นี่ หากคุณต้องการอัปเดตสถานะทุก ๆ 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!")
}
}
เรียกใช้ฟังก์ชัน wrapper ในสมาชิกของคุณ
store.subscribe((state) =>
{
updateLocalStorage(store.getState())
});
ในตัวอย่างนี้สถานะจะได้รับการอัปเดตไม่เกิน 5 วินาทีโดยไม่คำนึงว่าจะมีการเรียกใช้การอัปเดตบ่อยเพียงใด
(state) => { updateLocalStorage(store.getState()) }
ในlodash.throttle
ลักษณะนี้store.subscribe(throttle(() => {(state) => { updateLocalStorage(store.getState())} }
และลบเวลาตรวจสอบตรรกะภายใน
คำแนะนำที่ยอดเยี่ยมและข้อความที่ตัดตอนมาจากคำตอบอื่น ๆ (และบทความระดับกลางของ Jam Creencia ) นี่เป็นคำตอบที่สมบูรณ์!
เราต้องการไฟล์ที่มี 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"]
}