Cách sử dụng Redux Persist trong React Native

Phần này giới thiệu redux-persist, một gói tự động hóa quá trình duy trì trạng thái từ cửa hàng Redux của bạn đến bộ nhớ thiết bị cục bộ, chẳng hạn như AsyncStoragetrong trường hợp của React Native. redux-persistcũng tái tạo lại cửa hàng Redux của bạn trong các lần khởi chạy ứng dụng tiếp theo, hay còn gọi là bù nước. Các tiện ích hữu ích này giảm thiểu công việc cần thiết để duy trì dữ liệu trên thiết bị, chẳng hạn như mã thông báo xác thực và cài đặt tài khoản.

Với redux-persist, quá trình này được thực hiện tự động và chỉ yêu cầu một lượng nhỏ bản ghi sẵn để khởi tạo. AsyncStoragelà cơ chế lưu trữ mà chúng tôi sẽ áp dụng trong phần này. Chúng tôi sẽ đề cập đến toàn bộ thiết lập này, cũng như xem xét cách mô đun hóa các bộ giảm tốc của bạn bằng cách lồng chúng và do đó giữ cho chúng có tổ chức hơn redux-persistđể làm việc.

redux-persisthoạt động cực kỳ hiệu quả với các bộ giảm được thiết kế tốt – điều mà các tài nguyên trực tuyến khác không liên quan đến. Điều quan trọng là có thể làm cho các bộ giảm bớt của bạn chi tiết khi cần thiết khi ứng dụng của bạn ngày càng phức tạp, để quản lý hiệu quả cửa hàng Redux của bạn. Phần này sẽ dành một phần cho mục đích này vì làm như vậy đi đôi với redux-persistviệc triển khai hiệu quả .

redux-persistkhông phụ thuộc vào nền tảng và không giả định bất kỳ điều gì về nền tảng bạn đang phát triển (mỗi nền tảng sẽ có các phương pháp lưu trữ dữ liệu khác nhau, chẳng hạn như localStorageđối với các ứng dụng dựa trên trình duyệt). Gói này, hiện đã có phiên bản 6, đang tìm nạp hơn 400.000 lượt tải xuống hàng tuần tại thời điểm viết bài và đã trở thành một thành phần tiêu chuẩn cho nhiều dự án trong hệ sinh thái Redux để đơn giản hóa việc quản lý nhà nước.

Do sự không thay đổi của Redux nói chung, không có bất kể bản update nào gần đây cho gói – và những bản update trong tương lai sẽ khó xảy ra trừ khi những đổi khác vi phạm được đưa vào Redux .

Redux Persist đồng bộ hóa và duy trì trạng thái ứng dụng giữa các phiên

redux-persistđảm bảo rằng trạng thái sẽ vẫn được lưu giữa các phiên ứng dụng. Nó sẽ khởi tạo cửa hàng Redux của bạn với bất kỳ trạng thái nào đã lưu trước đó khi khởi chạy ứng dụng và sẽ giữ trạng thái ứng dụng tồn tại này đồng bộ với trạng thái ứng dụng hiện tại. Nếu không có trạng thái ổn định như vậy, ứng dụng của bạn sẽ đặt lại về cài đặt cửa hàng [Redux] mặc định sau mỗi lần đóng ứng dụng.

Hãy nghĩ đến mã thông báo xác thực giúp người dùng luôn đăng nhập vào ứng dụng của bạn – bạn muốn mã thông báo này tồn tại miễn là nó hợp lệ. Mỗi khi người dùng mở ứng dụng, ứng dụng sẽ có thể tìm nạp mã thông báo đó từ đó AsyncStorage. Quá trình tìm nạp một cửa hàng đã lưu trước đó được gọi là bù nước với redux-persist; chúng ta sẽ khám phá quá trình này sâu hơn trong bài viết.

Cửa hàng Redux cũng sẽ được gọi đơn giản là “cửa hàng” trong suốt bài viết này. Cửa hàng Redux là một đối tượng JSON đại diện cho trạng thái ứng dụng của bạn được quản lý thông qua bộ giảm trong Redux. Nếu người đọc chưa quen với Redux, hãy xem bài viết giới thiệu Redux cho React: Giới thiệu đơn giản của tôi .

Bạn hoàn toàn có thể quản lý các quy trình như vậy một cách riêng biệt với Redux bằng cách gọi thủ công AsyncStoragekhi cửa hàng của bạn cập nhật hoặc khi các thay đổi trạng thái quan trọng xảy ra trong ứng dụng của bạn. Nhưng như chúng ta sẽ khám phá tiếp theo, cách tiếp cận này có thể trở nên rắc rối khi ứng dụng của bạn ngày càng phức tạp.

Tiếp theo, chúng tôi sẽ tổng quan ngắn gọn về ngữ cảnh mà Redux Persist tránh và đề cập đến một số ít cấu trúc Reduceer mê hoặc, trước khi chuyển sang tích hợp redux-Kiên trì vào một dự án Bất Động Sản React Native .

Vấn đề Redux Persist giải quyết

Redux Persist có hai quyền lợi chính :

  • Nó giảm thiểu mã soạn sẵn của bạn và giữ trạng thái ứng dụng của bạn được quản lý chặt chẽ bởi Redux.
  • Nó loại bỏ nhu cầu viết AsyncStoragecác cuộc gọi theo cách thủ công để duy trì trạng thái ứng dụng, nơi bạn thường viết các lệnh gọi quản lý trạng thái cho Redux và AsyncStorageriêng biệt.

Trong bài viết đó, cả Redux và AsyncStorageđược sử dụng đồng thời để cập nhật trạng thái ứng dụng khi danh sách được cuộn qua, như sơ đồ sau minh họa:

Quy trình làm việc để tìm nạp thêm các mục danh sách trong khi cuộn

Điều này hợp lệ và hoàn toàn có thể đồng ý được, nhưng chúng tôi phải phối hợp hai nguồn tài liệu ; một cho trạng thái ứng dụng hiện tại và một cho trạng thái sống sót trên thiết bị. Điều này đi kèm với những yếu tố riêng của nó :

  • Việc biết nguồn nào là nguồn dữ liệu thực sự trở nên mờ nhạt; trạng thái tồn tại trước đó sẽ là nguồn thực khi khởi chạy ứng dụng, trong khi cửa hàng Redux sẽ là nguồn thực khi người dùng đang tích cực tương tác với ứng dụng.
  • Bạn càng thực hiện nhiều lệnh gọi đến cả Redux và AsyncStorageđồng thời, mã của bạn càng trở nên lộn xộn, khiến việc đọc và bảo trì càng khó khăn hơn.
  • Ngày càng khó để khớp bộ lưu trữ khóa-giá trị của bạn với bộ lưu trữ trạng thái Redux và do đó giữ cho cấu trúc dữ liệu của bạn được đồng bộ. Bạn thực sự có thể sao chép toàn bộ cửa hàng và JSON.stringify()nó vào AsyncStorage, nhưng điều này đi kèm với các vấn đề riêng – ví dụ: nếu một bản cập nhật ứng dụng thay đổi cấu trúc cửa hàng của bạn, trạng thái tồn tại của bạn sẽ không đồng bộ và bạn phải tạo API theo cách thủ công để thay thế hoặc cấu trúc lại trạng thái tồn tại.

Điều này có thể đạt được bằng cách thiết lập Ranh giới lỗi, khi được kích hoạt, sẽ xóa sạch dữ liệu tồn tại và chuyển hướng trở lại màn hình đăng nhập của bạn (hoặc màn hình ứng dụng đầu tiên). Tôi đã xuất bản một giải pháp như vậy trong React Native: Làm việc với ranh giới lỗi .

Lưu ý rằng Ranh giới Lỗi thuận tiện bắt lỗi ( ví dụ điển hình như thiếu thuộc tính từ shop Redux ) và hoàn toàn có thể cung ứng một thành phần riêng không liên quan gì đến nhau được hiển thị trong sự kiện và lỗi được kích hoạt .

Để giảm thiểu các vấn đề đã thảo luận ở đây, chúng tôi muốn xóa AsyncStoragethành phần khỏi sơ đồ trên và chỉ dựa vào cửa hàng Redux làm nguồn dữ liệu thực sự. redux-persistsẽ thực hiện tất cả công việc giữ cho dữ liệu được đồng bộ hóa và bù nước cho dữ liệu khi khởi chạy ứng dụng tiếp theo.

Trước khi đi sâu vào việc triển khai redux-persist, hãy xem cách chúng tôi có thể tận dụng các bộ giảm để cấu trúc hiệu quả cửa hàng Redux của bạn. Như chúng tôi sẽ trình bày sâu hơn, redux-persistcó thể tồn tại hoặc bỏ qua một tập hợp con của cửa hàng Redux của bạn, vì vậy điều quan trọng là phải cấu trúc các bộ giảm bớt của bạn với ý định bao gồm hoặc bỏ qua cấu trúc cửa hàng tương ứng của nó ở trạng thái tồn tại.

Bộ giảm cấu trúc và làm tổ

Cấu trúc bộ giảm cấu trúc theo cách mô-đun và hiệu quả để khen ngợi cấu trúc dữ liệu cửa hàng của bạn là chìa khóa trong việc tận dụng tất cả những gì redux-persistphải cung cấp.

Cho đến giờ đây, bạn hoàn toàn có thể chỉ cần tích hợp những bộ giảm từ một tệp chỉ mục, với cấu trúc sau :

// simple multi-reducer setup
reducers/
   account.js
   auth.js
   index.js
   plans.js
   sessions.js
// reducers/index.js
import account from './account'
import auth from './auth'
...
export default combineReducers({
   account,
   auth,
   ...
});

Gọi bộ giảm tốc từ bộ giảm tốc khác

Điều đáng chú ý là trình giảm thiểu sử dụng khóa tên của nó theo mặc định. Ví dụ: trình giảm xác thực sẽ quản lý các cập nhật trạng thái đối với authkhông gian tên theo mặc định và tại store.authtrạng thái cửa hàng của bạn. Điều này có thể được thay đổi đơn giản bằng cách cung cấp một khóa bên trong combineReducersvà có thể hữu ích nếu bạn muốn có một quy ước đặt tên thành ngữ hơn:

// providing a reducer namespace manually
import authReducer from './auth'
...
export default combineReducers({
   auth: authReducer,
   ...
});
// reducers/auth.js
import settingsReducer from ./settings'
function authReducer(state = {}, action) {
  switch (action.type) {
    case SET_AUTH_SETTINGS:
      return {
         ...state, 
         settings: settingsReducer(state.settings, action)
      }
   }
}

Khi ứng dụng của bạn ngày càng phức tạp, việc phân loại thêm những bộ giảm bớt bằng cách lồng chúng vào nhau hoàn toàn có thể mang lại hiệu suất cao. Để chứng minh điều này, chúng tôi sẽ lan rộng ra trình giảm auth để nó sẽ phối hợp những trình giảm từ thư mục của chính nó :

// nested reducer setup
reducers/
   account.js
   auth/
      account.js
      index.js
      subscription.js
      security.js
   index.js
   plans.js
   ...
// reducers/auth/index.js
import { combineReducers } from 'redux'
import account from './account'
import security from './security'
import subscription from './subscription'

export default combineReducers({
  account,
  security,
  subscription,
});

Bây giờ, lý do liên quan đến điều redux-persistnày là chúng tôi có thể đưa vào danh sách đen hoặc danh sách trắng các phần nhất định trong cửa hàng của bạn được duy trì – chúng tôi có thể chọn một cách hiệu quả những phần nào của cửa hàng mà chúng tôi muốn tồn tại và không muốn tồn tại. Chúng tôi có thể tồn tại store.auth, nhưng store.plansví dụ như danh sách đen .

Chúng tôi sẽ xem thêm về cách định thông số kỹ thuật những thiết lập này trong những tệp trình giảm bớt của bạn để có một tổ chức triển khai ngặt nghèo hơn .
Do đó, sẽ có ý nghĩa khi cấu trúc logic rút gọn của bạn sao cho bạn tách biệt những logic nào mà bạn dự tính liên tục. Hơn nữa, chú thích một tệp với nhận xét nhắc nhở những nhà tăng trưởng liệu một trình giảm thiểu có giải quyết và xử lý trạng thái sống sót hay không cũng hoàn toàn có thể thực thi được với quy mô này .

Tích hợp Redux Persist

Bây giờ chúng ta sẽ chuyển sự chú ý sang tích hợp react-persistvới một cửa hàng Redux. Điều này có thể được thực hiện trong App.jstệp của bạn hoặc nơi bạn muốn tạo cửa hàng Redux của mình.

Thiết lập cơ bản Redux Persist

Đầu tiên, hãy nhập các thành phần cần thiết để duy trì redux store. Lưu ý rằng chúng tôi vẫn đang dựa trên các reduxAPI cơ bản :

// basic redux boilerplate
import { createStore } from 'redux'
import { Provider } from 'react-redux'
// redux-persist wrappers
import { persistStore, persistReducer } from 'redux-persist'
// the local storage we'll be using to persist data
import AsyncStorage from '@react-native-community/async-storage'
// redux-persist merge level
import autoMergeLevel2 from 'redux persist/lib/stateReconciler/autoMergeLevel2'
// root reducer - reducers/index.js
import rootReducer from './reducers'
// the component we'll use to wrap our component tree
import { PersistGate } from 'redux-persist/lib/integration/react';
  • persistStorepersistReducerbọc cửa hàng và cửa hàng của bạn tương ứng. Chúng ta sẽ xem các ví dụ về điều này bên dưới, nơi chúng ta bọc bộ giảm tốc gốc.
  • Redux Persist cần biết sử dụng hệ thống lưu trữ nào để duy trì cửa hàng được đề cập. Đây sẽ là AsyncStorageđiều mà chúng ta sẽ xác định trong đối tượng cấu hình tiếp theo.
  • Mức hợp nhất quy định mức độ dữ liệu xuống thấp sẽ được thay thế. Trong trường hợp này, chúng tôi đã chọn tối đa 2 cấp độ sâu qua autoMergeLevel2, chỉ ghi đè các thuộc tính đang được bù nước ở cấp độ 1 và 2. Các thuộc tính có ở dưới cấp độ này ở trạng thái ban đầu nhưng không có trong trạng thái duy trì sẽ bị xóa .
  • Một thành phần cũng đã được nhập, bao bọc cây thành phần của bạn bên dưới thành phần của Redux. trì hoãn việc hiển thị các thành phần con của nó cho đến khi cửa hàng được truy xuất và lưu trong Redux. Nó cũng hỗ trợ một giá loadingđỡ tùy chọn, cho phép bạn hiển thị một bộ tải trong khi cửa hàng đang được bù nước.
// persist config
const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  stateReconciler: autoMergeLevel2
};
// wrap persist API around root reducer and store
const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore(persistedReducer);
export const persistor = persistStore(store);
// App component
const App = () => {
  return (
    
      
        
      
    
  );
};

export default App;

Giải pháp này bây giờ sẽ duy trì toàn bộ cửa hàng Redux của bạn vào AsyncStoragevà tái tạo (bù nước) cho nó khi một ứng dụng tải lại. Phần tiếp theo sẽ khám phá cách chúng tôi có thể bao gồm hoặc bỏ qua các phần của cửa hàng để được duy trì.

Làm việc với danh sách đen và danh sách trắng

blacklisthoặc whitelistcác thuộc tính có thể được cấu hình bên trong persistConfigđối tượng của bạn dưới dạng các mảng khóa giảm tốc mà bạn muốn bỏ qua hoặc đưa vào AsyncStorage. Định nghĩa blacklistsẽ bao gồm tất cả các trạng thái khác theo mặc định, trong khi định nghĩa whitelistsẽ bỏ qua tất cả các trạng thái khác theo mặc định. Chỉ cần liệt kê các bộ giảm tốc của bạn để định cấu hình:

// defining a blacklist
const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  stateReconciler: autoMergeLevel2,
  blacklist: ['plans', 'session'],
};

Nếu bạn đang làm việc để tích hợp redux-persistvào một dự án hiện có, có thể khôn ngoan hơn khi sử dụng thuộc whitelisttính để giới thiệu một bộ giảm tốc tại một thời điểm, từ từ chuyển trạng thái tồn tại của bạn từ thiết lập thủ công. Chúng tôi sẽ thêm chi tiết hơn nữa về những bộ giảm phụ hoặc thậm chí các thuộc tính riêng lẻ có thể được đưa vào danh sách trắng hơn nữa.

Nhưng mọi thứ trở nên thú vị hơn một chút nếu chúng ta muốn bỏ qua các thuộc tính từ các bộ khử lồng nhau. Để đạt được điều này, chúng ta có thể bao bọc các bộ giảm tốc riêng lẻ persistReducercùng với cấu hình riêng của nó và do đó các thuộc tính danh sách đen đề cập đến bộ giảm tốc được đề cập.

Đây là nơi mà các bộ giảm thiểu lồng nhau của chúng ta nói chuyện từ phía trên trở nên hữu ích. Chúng tôi có thể tối ưu hóa việc tổ chức persistReducercấu hình trên cơ sở từng bộ giảm thiểu, điều này trở nên dễ dàng hơn nhiều nếu chúng được phân tách một cách hợp lý.

Vì vậy, giả sử chúng tôi muốn bỏ qua thuộc auth.securitytính, các bản cập nhật của thuộc tính này nằm trong miền của trình authgiảm thiểu lồng nhau. Chúng ta có thể đơn giản xác định một persistConfigđối tượng bên trong /reducers/auth/index.jsvà bọc bộ giảm tốc persistReducertại thời điểm xuất. Quay lại authtệp trình giảm thiểu lồng nhau, bây giờ chúng ta có thể thêm API cần thiết với các thay đổi được tô đậm:

// reducers/auth/index.js
import { combineReducers } from 'redux'
import account from './account'
import security from './security'
import subscription from './subscription'
import AsyncStorage from '@react-native-community/async-storage'
import { persistReducer } from 'redux-persist';
const persistConfig = {
  key: 'auth',
  storage: AsyncStorage,
  blacklist: ['security']
};
const authReducer = combineReducers({
  account,
  security,
  subscription,
});
export default persistReducer(persistConfig, authReducer);

Nơi nào nên xác định các đối tượng Perspiconfig?

Có nên persistConfigxác định tất cả các đối tượng trong một tệp, chẳng hạn như tệp giảm tốc gốc của bạn tại /reducers/index.js? Ví dụ trên đã chọn xác định cấu hình tồn tại trong tệp trình giảm thiểu lồng nhau tương ứng. Điều này hợp lý khi bao gồm dọc theo combineReducers, điểm mà tại đó các bộ giảm được tổng hợp.

Trường hợp thay thế là xác định mọi thứ trong một tệp – tốt nhất là bên trong tệp giảm tốc gốc. Nếu đúng như vậy, chúng ta cũng có thể bọc các bộ giảm cấp cao nhất với persistReducertrực tiếp bên trong bộ giảm gốc. Điều này được thể hiện trong ví dụ sau, với các thay đổi được tô đậm một lần nữa:

// reducers/index.js
...
// define persistConfig objects for needed reducers
const rootPersistConfig = {
  key: 'root',
  storage: AsyncStorage,
};

const authPersistConfig = {
  key: 'auth',
  storage: AsyncStorage,
  blacklist: ['security']
};
const rootReducer = combineReducers({
   account,
   auth: persistReducer(authPersistConfig, authReducer),
   ...
});
export default persistReducer(rootPersistConfig, rootReducer);

Chúng tôi cũng có thể đặt exporttừ khóa bên cạnh mỗi từ khóa persistConfigđược yêu cầu cho các bộ giảm lồng nhau và nhập chúng từ các tệp tương ứng của chúng. Ít nhất trong trường hợp đó, tất cả logic tồn tại sẽ ở một nơi. Sự lựa chọn cuối cùng nằm trong tay của nhà phát triển!

Đề cập đến chuyển đổi

Chuyển đổi là một tính năng khác của Redux Persist được cho phép bạn tùy chỉnh đối tượng người dùng trạng thái được duy trì và bù nước. Đây là một chủ đề nâng cao đa phần nằm ngoài khoanh vùng phạm vi của phần này, với một số ít trường hợp sử dụng hạn chế, nhưng về cơ bản những quy đổi được cho phép bạn giải quyết và xử lý thêm trạng thái vì nó đang được duy trì hoặc được bù nước .
Một biến hóa mà tôi thấy mê hoặc là biến hóa nén, được cho phép một đổi khác giảm thiểu trạng thái trước khi duy trì nó vào bộ nhớ cục bộ .

Để đọc thêm về các phép chuyển đổi, tài liệu chính thức trên GitHub chứa danh sách các phép biến đổi và khả năng của chúng.

Tóm tắt

Bài viết này đã đặt ra trường hợp redux-persist, cấu trúc bộ giảm hiệu quả có thể hỗ trợ như thế nào trong quá trình định cấu hình trạng thái bền vững và bao gồm một hướng dẫn để tích hợp redux-persistvào một dự án React Native.

Gói này cực kỳ hữu ích khi bạn có một kho lưu trữ Redux phức tạp, một số hoặc tất cả các nhu cầu cần được duy trì vào bộ nhớ cục bộ. redux-persistloại bỏ nhu cầu quản lý sự tồn tại này bên ngoài các bản cập nhật cửa hàng Redux hợp nhất trạng thái ứng dụng của bạn thành một API.

Rate this post