Làm cách nào để duy trì cây trạng thái redux khi làm mới?


92

Nguyên tắc đầu tiên của tài liệu Redux là:

Trạng thái của toàn bộ ứng dụng của bạn được lưu trữ trong một cây đối tượng trong một cửa hàng duy nhất.

Và tôi thực sự nghĩ rằng tôi hiểu rõ tất cả các hiệu trưởng. Nhưng bây giờ tôi đang bối rối ứng dụng nghĩa là gì.

Nếu ứng dụng chỉ là một phần nhỏ phức tạp trong trang web và hoạt động chỉ trong một trang, tôi hiểu. Nhưng nếu ứng dụng có nghĩa là toàn bộ trang web? Tôi có nên sử dụng LocalStorage hoặc cookie hoặc thứ gì đó để giữ cây trạng thái không? nhưng nếu trình duyệt không hỗ trợ LocalStorage thì sao?

Tôi muốn biết cách các nhà phát triển giữ cây trạng thái của họ! :)


2
Đó là một loại câu hỏi rộng. Bạn có thể làm bất kỳ điều gì bạn đã đề cập. Bạn có mã nào muốn chia sẻ để cho chúng tôi biết những gì bạn đã thử và không hiệu quả không? Bạn có thể triển khai toàn bộ trang web của mình thành một thực thể duy nhất hoặc bạn có thể có nhiều. Bạn có thể sử dụng localStorage để duy trì dữ liệu hoặc một DB thực hoặc không. Ứng dụng có nghĩa là cá thể sống, hoạt động. Trong hầu hết các trường hợp, đây chỉ là một, gốc của bạn. Nhưng, một lần nữa, có nhiều cách để thực hiện các ứng dụng.
ZekeDroid

Câu trả lời:


88

Nếu bạn muốn duy trì trạng thái redux của mình trong quá trình làm mới trình duyệt, tốt nhất bạn nên thực hiện việc này bằng cách sử dụng phần mềm trung gian redux. Kiểm tra các Redux-kiên trìRedux-lưu trữ trung gian. Cả hai đều cố gắng thực hiện cùng một nhiệm vụ là lưu trữ trạng thái redux của bạn để nó có thể được lưu và tải theo ý muốn.

-

Biên tập

Đã một thời gian kể từ khi tôi xem lại câu hỏi này, nhưng thấy rằng câu hỏi khác (mặc dù câu trả lời được ủng hộ nhiều hơn) khuyến khích đưa ra giải pháp của riêng bạn, tôi nghĩ rằng tôi sẽ trả lời lại câu hỏi này.

Kể từ lần chỉnh sửa này, cả hai thư viện đã được cập nhật trong vòng sáu tháng qua. Nhóm của tôi đã sử dụng redux-Kiên trì sản xuất trong vài năm nay và không gặp vấn đề gì.

Mặc dù nó có vẻ là một vấn đề đơn giản, nhưng bạn sẽ nhanh chóng nhận thấy rằng việc áp dụng giải pháp của riêng bạn sẽ không chỉ gây ra gánh nặng bảo trì mà còn dẫn đến lỗi và các vấn đề về hiệu suất. Những ví dụ đầu tiên xuất hiện trong tâm trí là:

  1. JSON.stringifyJSON.parsekhông chỉ có thể làm ảnh hưởng đến hiệu suất khi không cần thiết mà còn tạo ra các lỗi mà khi được xử lý trong một đoạn mã quan trọng như cửa hàng redux của bạn có thể làm hỏng ứng dụng của bạn.
  2. (Được đề cập một phần trong câu trả lời bên dưới): Tìm ra thời điểm và cách lưu và khôi phục trạng thái ứng dụng của bạn không phải là một vấn đề đơn giản. Làm điều đó quá thường xuyên và bạn sẽ làm giảm hiệu suất. Không đủ hoặc nếu các phần trạng thái sai vẫn tiếp diễn, bạn có thể thấy mình có nhiều lỗi hơn. Các thư viện được đề cập ở trên đã được thử nghiệm thực chiến trong cách tiếp cận của họ và cung cấp một số cách tùy chỉnh hành vi của chúng khá dễ bị đánh lừa.
  3. Một phần của vẻ đẹp của redux (đặc biệt là trong hệ sinh thái React) là khả năng được đặt trong nhiều môi trường. Tính đến bản chỉnh sửa này, redux-Kiên trì có 15 cách triển khai lưu trữ khác nhau , bao gồm thư viện localForage tuyệt vời cho web, cũng như hỗ trợ cho React Native, Electron và Node.

Tóm lại, đối với 3kB minified + gzipped (tại thời điểm chỉnh sửa này), đây không phải là vấn đề mà tôi sẽ yêu cầu nhóm của mình tự giải quyết.


5
Tôi có thể giới thiệu redux-Kiên trì (chưa thử redux-storage) nhưng nó hoạt động khá tốt đối với tôi chỉ với rất ít cấu hình và thiết lập.
larrydahooster

Kể từ ngày này, cả hai thư viện đều đã chết và không được duy trì với các cam kết cuối cùng cách đây 2 năm.
AnBisw

1
trông giống như Redux-tồn tại là trở lại một chút, với một mới công bố 22 ngày trước tại thời điểm viết bài của tôi
Zeragamba

Các vị trí mới của Redux-lưu trữ là github.com/react-stack/redux-storage
Michael Freidgeim

2
LƯU Ý VỀ CÂU TRẢ LỜI NÀY: Thực tế là phần mềm & thư viện nói chung đã áp dụng cách tiếp cận dựa trên cộng đồng (hỗ trợ) mà ngay cả một số mô-đun rất quan trọng của ngôn ngữ lập trình cũng được hỗ trợ bởi các bên / thư viện thứ ba. Nói chung, nhà phát triển phải theo dõi mọi công cụ được sử dụng trong ngăn xếp của mình để biết liệu nó có bị ngừng sử dụng / cập nhật hay không. Hai lựa chọn; 1. Triển khai của riêng bạn và tiếp tục phát triển mãi mãi để đảm bảo hiệu suất và các tiêu chuẩn nền tảng chéo. 2. Sử dụng giải pháp đã được thử nghiệm trong trận chiến và chỉ kiểm tra các bản cập nhật / đề xuất như @ MiFreidgeimSO-stopbeingevil nói
Geek Guy

80

Chỉnh sửa ngày 25 tháng 8 năm 2019

Như đã nêu trong một trong các bình luận. Gói lưu trữ redux ban đầu đã được chuyển sang ngăn xếp phản ứng . Cách tiếp cận này vẫn tập trung vào việc thực hiện giải pháp quản lý nhà nước của riêng bạn.


Câu trả lời gốc

Mặc dù câu trả lời được cung cấp là hợp lệ tại một số thời điểm, nhưng điều quan trọng cần lưu ý là gói lưu trữ redux ban đầu đã không được dùng nữa và nó không còn được duy trì nữa ...

Tác giả ban đầu của gói redux-storage đã quyết định không chấp nhận dự án và không còn được duy trì.

Bây giờ, nếu bạn không muốn có sự phụ thuộc vào các gói khác để tránh những vấn đề như thế này trong tương lai, rất dễ dàng để đưa ra giải pháp của riêng bạn.

Tất cả những gì bạn cần làm là:

1- Tạo một hàm trả về trạng thái từ localStorageđó và sau đó truyền trạng thái cho createStorehàm redux của 'trong tham số thứ hai để hydrate hóa cửa hàng

 const store = createStore(appReducers, state);

2- Nghe các thay đổi trạng thái và mỗi khi trạng thái thay đổi, hãy lưu trạng thái vào localStorage

store.subscribe(() => {
    //this is just a function that saves state to localStorage
    saveState(store.getState());
}); 

Và đó là nó ... Tôi thực sự sử dụng một cái gì đó tương tự trong sản xuất, nhưng thay vì sử dụng các hàm, tôi đã viết một lớp rất đơn giản như bên dưới ...

class StateLoader {

    loadState() {
        try {
            let serializedState = localStorage.getItem("http://contoso.com:state");

            if (serializedState === null) {
                return this.initializeState();
            }

            return JSON.parse(serializedState);
        }
        catch (err) {
            return this.initializeState();
        }
    }

    saveState(state) {
        try {
            let serializedState = JSON.stringify(state);
            localStorage.setItem("http://contoso.com:state", serializedState);

        }
        catch (err) {
        }
    }

    initializeState() {
        return {
              //state object
            }
        };
    }
}

và sau đó khi khởi động ứng dụng của bạn ...

import StateLoader from "./state.loader"

const stateLoader = new StateLoader();

let store = createStore(appReducers, stateLoader.loadState());

store.subscribe(() => {
    stateLoader.saveState(store.getState());
});

Hy vọng nó sẽ giúp ai đó

Lưu ý Hiệu suất

Nếu các thay đổi trạng thái diễn ra rất thường xuyên trong ứng dụng của bạn, thì việc lưu vào bộ nhớ cục bộ quá thường xuyên có thể ảnh hưởng đến hiệu suất ứng dụng của bạn, đặc biệt nếu biểu đồ đối tượng trạng thái để tuần tự hóa / deserialize lớn. Đối với những trường hợp này, bạn có thể muốn debounce hoặc điều tiết chức năng tiết kiệm nhà nước để localStorage sử dụng RxJs, lodashhoặc một cái gì đó tương tự.


11
Thay vì sử dụng phần mềm trung gian, tôi thích cách tiếp cận này hơn. Cảm ơn những lời khuyên liên quan đến hiệu suất.
Joe zhou

1
Chắc chắn là câu trả lời ưa thích. Tuy nhiên, khi tôi làm mới trang và nó tải trạng thái từ localstorage khi tạo cửa hàng, tôi nhận được một số cảnh báo bao gồm văn bản "Thuộc tính không mong đợi [tên vùng chứa] được tìm thấy ở trạng thái trước được trình giảm thiểu nhận được. Dự kiến ​​sẽ tìm thấy một trong các thay vào đó là tên thuộc tính giảm thiểu đã biết: "global", "language". Các thuộc tính không mong muốn sẽ bị bỏ qua. Nó vẫn hoạt động và về cơ bản phàn nàn rằng tại thời điểm tạo cửa hàng, nó không biết về tất cả các vùng chứa khác. Có con đường xung quanh cảnh báo này?
Zief

@Zief khó nói. Thông báo "có vẻ" khá rõ ràng, các bộ giảm đang mong đợi các thuộc tính không được chỉ định. Nó có thể là một cái gì đó liên quan đến việc cung cấp các giá trị mặc định cho trạng thái tuần tự hóa?
Leo

Giải pháp rất đơn giản. Cảm ơn bạn.
Ishara Madawa

1
@Joezhou rất muốn biết lý do tại sao bạn thích cách tiếp cận này. Cá nhân, đây có vẻ như là thứ chính xác mà phần mềm trung gian dành cho.
michaelgmcd

1

Điều này dựa trên câu trả lời của Leo (đó phải là câu trả lời được chấp nhận vì nó đạt được mục đích của câu hỏi mà không cần sử dụng bất kỳ câu trả lời nào của bên thứ 3).

Tôi đã tạo một lớp Singleton tạo Redux Store, duy trì nó bằng cách sử dụng lưu trữ cục bộ và cho phép truy cập đơn giản vào cửa hàng của nó thông qua một getter .

Để sử dụng nó, chỉ cần đặt phần tử Redux-Provider sau đây xung quanh lớp chính của bạn:

// ... Your other imports
import PersistedStore from "./PersistedStore";

ReactDOM.render(
  <Provider store={PersistedStore.getDefaultStore().store}>
    <MainClass />
  </Provider>,
  document.getElementById('root')
);

và thêm lớp sau vào dự án của bạn:

import {
  createStore
} from "redux";

import rootReducer from './RootReducer'

const LOCAL_STORAGE_NAME = "localData";

class PersistedStore {

  // Singleton property
  static DefaultStore = null;

  // Accessor to the default instance of this class
  static getDefaultStore() {
    if (PersistedStore.DefaultStore === null) {
      PersistedStore.DefaultStore = new PersistedStore();
    }

    return PersistedStore.DefaultStore;
  }

  // Redux store
  _store = null;

  // When class instance is used, initialize the store
  constructor() {
    this.initStore()
  }

  // Initialization of Redux Store
  initStore() {
    this._store = createStore(rootReducer, PersistedStore.loadState());
    this._store.subscribe(() => {
      PersistedStore.saveState(this._store.getState());
    });
  }

  // Getter to access the Redux store
  get store() {
    return this._store;
  }

  // Loading persisted state from localStorage, no need to access
  // this method from the outside
  static loadState() {
    try {
      let serializedState = localStorage.getItem(LOCAL_STORAGE_NAME);

      if (serializedState === null) {
        return PersistedStore.initialState();
      }

      return JSON.parse(serializedState);
    } catch (err) {
      return PersistedStore.initialState();
    }
  }

  // Saving persisted state to localStorage every time something
  // changes in the Redux Store (This happens because of the subscribe() 
  // in the initStore-method). No need to access this method from the outside
  static saveState(state) {
    try {
      let serializedState = JSON.stringify(state);
      localStorage.setItem(LOCAL_STORAGE_NAME, serializedState);
    } catch (err) {}
  }

  // Return whatever you want your initial state to be
  static initialState() {
    return {};
  }
}

export default PersistedStore;

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.