Lưu Redux state vào local storage với redux-persist

Chúng tôi rất vui mừng chia sẻ kiến thức sâu sắc về từ khóa Redux persist la gi và hi vọng rằng nó sẽ hữu ích cho các bạn đọc. Bài viết tập trung trình bày ý nghĩa, vai trò và ứng dụng của từ khóa trong việc tối ưu hóa nội dung trang web và chiến dịch tiếp thị trực tuyến. Chúng tôi cung cấp các phương pháp tìm kiếm, phân tích và chọn lọc từ khóa phù hợp, kèm theo các chiến lược và công cụ hữu ích. Hi vọng rằng thông tin chúng tôi chia sẻ sẽ giúp bạn xây dựng chiến lược thành công và thu hút lưu lượng người dùng. Cảm ơn sự quan tâm và hãy tiếp tục theo dõi blog của chúng tôi để cập nhật kiến thức mới nhất.

Redux Persist nhận vào Redux state object của bạn và lưu nó vào các bộ nhớ nội bộ. Sau đó khi app phát động thì nó sẽ lấy các state này ra và lưu trở lại vào Redux.

Bạn Đang Xem: Lưu Redux state vào local storage với redux-persist

Mở màn sử dụng

Dependencies

npm install -save redux-persist – hoặc – yarn add redux-persist

Implementation

Khi tạo Redux store, truyền vào hàm createStore của bạn một hàm persistReducer có tác dụng đóng gói reducer gốc trong app của bạn. Một khi store đã được khởi tạo, truyền nó vào hàm persistStore để đảm bảo Redux state sẽ tiến hành lưu vào storage mỗi lúc nó thay đổi.

// src/store/index.js import { createStore } from ‘redux’; import { persistStore, persistReducer } from ‘redux-persist’; import storage from ‘redux-persist/lib/storage’; import autoMergeLevel2 from ‘redux-persist/lib/stateReconciler/autoMergeLevel2’; import rootReducer from ‘./reducers’; // giá trị trả về từ combineReducers const persistConfig = { key: ‘root’, storage: storage, stateReconciler: autoMergeLevel2 // Xem thêm tại mục “Quá trình merge”. }; const pReducer = persistReducer(persistConfig, rootReducer); export const store = createStore(pReducer); export const persistor = persistStore(store);

Nếu như bạn đang dùng React, gói root component của bạn trong PersistGate. Nó sẽ delay quá trình render UI app của bạn cho đến lúc state đã được lấy ra và lưu trở lại vào Redux.

import React from ‘react’; import { Provider } from ‘react-redux’; import { PersistGate } from ‘redux-persist/lib/integration/react’; import { persistor, store } from ‘./store’; import { RootComponent, LoadingView } from ‘./components’; const App = () => { return ( <Provider store={store}> // 2 props loading và persistor đều yêu cầu phải có <PersistGate loading={<LoadingView />} persistor={persistor}> <RootComponent /> </PersistGatevàgt; </Providervàgt; ); }; export default App;

Tùy chỉnh những gì sẽ tiến hành lưu

Nếu như bạn không muốn lưu một trong những phần nào đó trong state, chúng ta cũng có thể cho nó vào blacklist. blacklist sẽ tiến hành thêm vào config object mà tất cả chúng ta sẽ sử dụng để setup PersistReducer.

const persistConfig = { key: ‘root’, storage: storage, blacklist: [‘navigation’] }; const pReducer = persistReducer(persistConfig, rootReducer); export const store = createStore(pReducer); export const persistor = persistStore(store);

blacklist nhận vào trong 1 mảng string. Mỗi string cần khớp với một trong những phần của state được quản lý bởi reducer mà bạn truyền vào persistReducer. Với ví dụ trên, nếu rootReducer được tạo thông qua hàm combineReducers thì tất cả chúng ta sẽ expect là navigation là 1 trong trong các reducer, như vậy này:

combineReducers({ auth: AuthReducer, navigation: NavReducer, notes: NotesReducer });

Trái lại, nếu khách hàng chỉ muốn lưu một trong những phần nào đó trong state thì tất cả chúng ta có thể dùng whitelist. Ví dụ với những reducer trên tất cả chúng ta chỉ muốn lưu auth thôi chẳng hạn:

const persistConfig = { key: ‘root’, storage: storage, whitelist: [‘auth’] };

Xem Thêm : DOI: ĐỊNH NGHĨA, CÁCH TRA CỨU VÀ TRÍCH DẪN – EdLab Asia

Vậy nếu tất cả chúng ta muốn blacklist một nested property thì sao? Ví dụ, giả thiết rằng state object của bsnj có một key auth và bạn muốn lưu auth.currentUser nhưng không lưu auth.isLoggingIn. Để làm được điều này, hãy gói AuthReducer vào trong 1 PersistReducer, và sau đó cho isLoggingIn vào blacklist.

// AuthReducer.js import storage from ‘redux-persist/lib/storage’; import { persistReducer } from ‘redux-persist’; const INITIAL_STATE = { currentUser: null, isLoggingIn: false }; const AuthReducer = (state = INITIAL_STATE, action) => { // reducer implementation }; const persistConfig = { key: ‘auth’, storage: storage, blacklist: [‘isLoggingIn’] }; export default persistReducer(persistConfig, AuthReducer);

Nếu như bạn muốn tất cả những config được để ở cùng một chỗ, thì thay vì để nó trong reducer tương ứng, chúng ta cũng có thể đưa hết chúng vào hàm combineReducers:

// src/reducers/index.js import { combineReducers } from ‘redux’; import storage from ‘redux-persist/lib/storage’; import { persistReducer } from ‘redux-persist’; import { authReducer, navReducer, notesReducer } from ‘./reducers’ const rootPersistConfig = { key: ‘root’, storage: storage, blacklist: [‘navigation’] }; const authPersistConfig = { key: ‘auth’, storage: storage, blacklist: [‘isLoggingIn’] }; const rootReducer = combineReducers({ auth: persistReducer(authPersistConfig, authReducer), navigation: navReducer, notes: notesReducer }); export default persistReducer(rootPersistConfig, rootReducer);

Quá trình merge

Khi app của bạn phát động, Redux sẽ set một state mặc định. Ngay sau đó, Redux Persist sẽ lấy state đã lưu từ storage. State này sau này sẽ được ghi đè lên trên các state mặc định.

Quá trình merge được cho là sẽ hoạt động một cách tự động hóa cho bạn. Tuy vậy, bạn cũng đều có thể có những xử lý riêng cho quá trình này. Ví dụ, ở những bản cũ hơn của Redux Persist thì tất cả chúng ta cần tự quản lý quy trình lấy lại state (rehydration) bằng phương pháp bắt action REHYDRATE trong reducer và sau đó lưu payload của action này vào Redux state.

import { REHYDRATE } from ‘redux-persist’; const INITIAL_STATE = { currentUser: null, isLoggingIn: false }; const AuthReducer = (state = INITIAL_STATE, action) => { switch (action.type) { case REHYDRATE: return { …state, currentUser: action.payload.currentUser }; // …handle other cases

kích hoạt REHYDRATE sẽ tiến hành dispatch bởi Redux Persist ngay sau thời điểm nó đã lấy được state từ storage. Nếu như bạn trả về một state object mới từ action REHYDRATE, nó sẽ là state cuối cùng bạn nhận được. Nhưng như đã nói ở trên thì ở phiên bản mới của Redux Persist thì bạn không nhất thiết phải bắt action bằng tay nữa, trừ khi chúng ta muốn kiểm soát việc state được khôi phục ra sao.

Tuy vậy, hãy cẩn thận với điều này…

Có một vấn đề mà bạn cần phải nắm được trong quá trình merge, nó liên quan đến việc quá trình merge state sẽ sâu đến mức nào. Ở trên tất cả chúng ta đã biết quá trình merge sẽ ghi đè state mặc định bằng state được lấy ra từ storage. Sau đây là cách nó hoạt động:

Giả sử state mặc định của tất cả chúng ta nhìn như vậy này, và tất cả chúng ta đang lưu toàn bộ các property:

// initial state { auth: { currentUser: null, isLoggingIn: false }, notes: [] }

App của tất cả chúng ta phát động, và đây là state đã được lưu:

// persisted state { auth: { currentUser: { firstName: ‘Mark’, lastName: ‘Newton’ }, isLoggingIn: false }, notes: [noteA, noteB, noteC] }

Mặc định thì quá trình merge sẽ đơn giản chỉ thay các state ở cấp cực tốt thôi. Trong code thì nó nhìn sẽ tương tự thế này:

const finalState = { …initialState }; finalState[‘auth’] = persistedState[‘auth’] finalState[‘notes’] = persistedState[‘notes’]

Xem Thêm : Nhiễm trùng giòi maggot, căn bệnh kì quái

Trong hồ hết các trường hợp thì như vậy là đủ, nhưng nếu khách hàng release version mới của app của bạn và set state mặc định của auth như vậy này thì sao:

const INITIAL_STATE = { currentUser: null, isLoggingIn: false, error: ” };

Bạn vững chắc sẽ muốn state object cuối cùng có chứa key error này. Nhưng state object được lưu lại không có key đó, và nó sẽ thay đổi hoàn toàn state mặc định trong quá trình merge. Tạm biệt key error.

Cách sửa cho trường hợp này là yêu cầu PersistReducer merge sâu 2 cấp. Trong mục Mở màn sử dụng, chúng ta cũng có thể đã thấy setting stateReconciler trong root PersistReducer.

import autoMergeLevel2 from ‘redux-persist/lib/stateReconciler/autoMergeLevel2’; const persistConfig = { key: ‘root’, storage: storage, ** stateReconciler: autoMergeLevel2** };

autoMergeLevel2 là config để merge sâu 2 cấp. Khi đối chiếu với state auth, điều đó có tức thị quá trình merge trước hết sẽ tạo một bản copy state mặc định của auth, và sau đó chỉ ghi đè những key trong object auth nếu nó đã được lưu. Bởi vì key error không được lưu, nó sẽ tiến hành giữ nguyên.

Tóm lại, bạn cần phải phải nhớ rằng PersistReducers mặc định sẽ sử dụng autoMergeLevel1, tức thị nó sẽ thay các state ở cấp cực tốt bằng những gì đã được lưu. Nếu như bạn không có những PersistReducer riêng để quản lý việc lưu state nào cho những key ở cấp cao này thì bạn vững chắc sẽ cần phải sử dụng autoMergeLevel2. Tôi thì thích tự set cấp merge và ko dùng hàm này, nhưng tùy vào bạn thôi.

Tùy biến nâng cao

Transforms

Transform được cho phép bạn tùy biến state object mà bạn đã lưu và phục hồi.

Khi state object được lưu, nó trước hết sẽ tiến hành serialize bằng JSON.stringify(). Nếu có những phần trong state object không thể map với JSON object, quá trình serialize có thể sẽ chuyển đổi những phần này theo những cách mà tất cả chúng ta không lường trước được. Ví dụ, kiểu Set trong Javascript không tồn tại trong JSON. Khi chúng ta serialize một Set bằng JSON.stringify(), nó sẽ trở thành một object rỗng. Vững chắc đây không phải là điều bạn muốn.

Sau này là một Transform có thể lưu một property thuộc kiểu Set đơn giản bằng phương pháp convert nó thành một mảng và trái lại. Với cách này, Set sẽ tiến hành convert thành Array, là một cấu trúc tài liệu được support trong JSON. Khi được lấy ra từ local storage, mảng lại được convert trái lại thành Set trước lúc lưu vào Redux store.

import { createTransform } from ‘redux-persist’; const SetTransform = createTransform( // transform state trước lúc nó được serialize và lưu (inboundState, key) => { // convert mySet thành một mảng. return { …inboundState, mySet: […inboundState.mySet] }; }, // transform state đang rất được phục hồi (outboundState, key) => { // convert mySet trở lại thành Set. return { …outboundState, mySet: new Set(outboundState.mySet) }; }, // khái niệm reducer nào sẽ vận dụng transform này. { whitelist: [‘someReducer’] } ); export default SetTransform;

Hàm createTransform nhận vào 3 thông số:

  • Một hàm được gọi ngay trước lúc lưu state.
  • Một hàm được gọi ngay trước lúc phục hồi state.
  • Một config object

Sau đó, transform cần được thêm vào config object của PersistReducer:

import storage from ‘redux-persist/lib/storage’; import { SetTransform } from ‘./Transforms’; const persistConfig = { key: ‘root’, storage: storage, transforms: [SetTransform] }; // …remaining implementation

Nội dung bài viết được dịch từ The Definitive Guide to Redux Persist của tác giả Mark Newton.

You May Also Like

About the Author: v1000