Yenileme sırasında yeniden düzenleme durum ağacını nasıl sürdürebilirim?


92

Redux dokümantasyonunun ilk sorumlusu:

Tüm uygulamanızın durumu, tek bir depodaki bir nesne ağacında saklanır.

Ve aslında tüm müdürleri iyi anladığımı düşündüm. Ama şimdi uygulamanın ne anlama geldiğini kafam karıştı.

Uygulama, web sitesinde yalnızca küçük karmaşık bir bölüm anlamına geliyorsa ve yalnızca bir sayfada çalışıyorsa, anlıyorum. Peki ya uygulama tüm web sitesi anlamına geliyorsa? Durum ağacını korumak için LocalStorage veya tanımlama bilgisi veya başka bir şey kullanmalı mıyım? ama ya tarayıcı LocalStorage'ı desteklemiyorsa?

Geliştiricilerin durum ağaçlarını nasıl koruduklarını bilmek istiyorum! :)


2
Bu çok geniş bir soru. Bahsettiğiniz herhangi bir şeyi yapabilirsiniz. Neyi denediğinizi ve çalışmadığınızı bize göstermek için paylaşmak istediğiniz kodunuz var mı? Tüm web sitenizi tek bir varlık olarak uygulayabilir veya birden çok kişiye sahip olabilirsiniz. Verileri kalıcı hale getirmek için localStorage'ı veya gerçek bir DB'yi veya ikisini birden kullanabilirsiniz. Uygulama yaşamak, aktif örnek demektir. Çoğu durumda bu sadece bir tanesidir, sizin kökünüz. Ancak, uygulamaları gerçekleştirmenin birçok yolu vardır.
ZekeDroid

Yanıtlar:


88

Redux durumunuzu bir tarayıcı yenilemesi boyunca sürdürmek istiyorsanız, bunu redux ara yazılımını kullanarak yapmak en iyisidir. Redux-persist ve redux-storage middleware'e göz atın . İkisi de aynı işi, yeniden düzenleme durumunuzu kaydetme görevini yerine getirmeye çalışır, böylece istenildiği zaman kaydedilebilir ve yüklenebilir.

-

Düzenle

Bu soruyu tekrar gözden geçirmeyeli biraz zaman oldu, ancak diğerinin (daha fazla oylanmış yanıt olsa da) kendi çözümünüzü yuvarlamayı teşvik ettiğini görünce, bunu tekrar yanıtlayacağımı düşündüm.

Bu düzenleme itibariyle, her iki kitaplık da son altı ay içinde güncellendi. Ekibim birkaç yıldır üretimde redux-persist kullanıyor ve herhangi bir sorun yaşamadı.

Basit bir sorun gibi görünse de, kendi çözümünüzü kullanmanın yalnızca bakım yüküne neden olmayacağını, aynı zamanda hatalara ve performans sorunlarına da yol açacağını çabucak göreceksiniz. Akla gelen ilk örnekler:

  1. JSON.stringifyve JSON.parsesadece ihtiyaç duyulmadığında performansa zarar vermekle kalmaz, aynı zamanda redux mağazanız gibi kritik bir kod parçasında işlenmediğinde uygulamanızı çökertebilecek hatalar da verir.
  2. (Aşağıdaki yanıtta kısmen bahsedilmiştir): Uygulamanızın durumunu ne zaman ve nasıl kaydedip geri yükleyeceğinizi bulmak basit bir sorun değildir. Bunu çok sık yaparsan performansın azalır. Yeterli değil veya devletin yanlış kısımları ısrar ederse, kendinizi daha fazla hatayla bulabilirsiniz. Yukarıda bahsedilen kütüphaneler, yaklaşımlarında savaş testine tabi tutulmuşlardır ve davranışlarını özelleştirmek için oldukça aptalca kanıtlanmış yöntemler sunarlar.
  3. Redux'un güzelliğinin bir kısmı (özellikle React ekosisteminde) birden fazla ortama yerleştirilebilmesidir. Bu düzenleme itibarıyla redux-persist, web için harika localForage kitaplığı ve React Native, Electron ve Node desteği de dahil olmak üzere 15 farklı depolama uygulamasına sahip .

Özetlemek gerekirse, 3kB küçültülmüş + gzip ile sıkıştırılmış (bu düzenleme sırasında) bu bir sorun değil, ekibimden kendi kendine çözmesini isterim.


5
Redux-persist'i önerebilirim (henüz redux-storage'u denemedim) ancak çok az yapılandırma ve kurulumla benim için oldukça iyi çalışıyor.
larrydahooster

Bu tarihten itibaren 2 yıl öncesine kadar hem kütüphaneler ölü görünüyor hem de son kayıtlarla sürdürülmüyor.
AnBisw

1
Görünüşe göre redux-persist, 22 gün önce yazdığım sırada yeni bir yayınla biraz geri döndü
Zeragamba


2
BU CEVAPLA İLGİLİ BUNA DİKKAT EDİN: Gerçek şu ki, yazılım ve kitaplıklar genellikle topluluk (destek) tabanlı bir yaklaşımı benimsemiştir , bir programlama dilinin çok önemli bazı modülleri bile üçüncü taraflar / kitaplıklar tarafından desteklenir. Genel olarak geliştiricinin, kullanımdan kaldırılıp güncellenmediğini / güncellenip güncellenmediğini bilmek için yığınında kullanılan her araca göz kulak olması gerekir. İki seçenek; 1. Kendinizinkini uygulayın ve performansı ve platformlar arası standartları garanti ederek sonsuza kadar geliştirmeye devam edin. 2. Savaşta test edilmiş çözümü kullanın ve yalnızca @ MiFreidgeimSO-stopbeingevil'in dediği gibi güncellemeleri / önerileri kontrol edin
Geek Guy

80

25 Ağustos 2019'u Düzenle

Yorumlardan birinde belirtildiği gibi. Orijinal yeniden depolama paketi react-stack'e taşındı . Bu yaklaşım hala kendi durum yönetimi çözümünüzü uygulamaya odaklanmaktadır.


Orijinal Cevap

Verilen yanıt bir noktada geçerli olsa da, orijinal yeniden düzenleme depolama paketinin kullanımdan kaldırıldığını ve artık korunmadığını fark etmek önemlidir ...

Yeniden depolama paketinin orijinal yazarı, projeyi kullanımdan kaldırmaya karar verdi ve artık sürdürülmedi.

Şimdi, gelecekte bu gibi sorunlardan kaçınmak için diğer paketlere bağımlı olmak istemiyorsanız, kendi çözümünüzü kullanmak çok kolaydır.

Yapmanız gereken tek şey:

1- Depoyu hidratlamak için ikinci parametrede durumu döndüren localStorageve ardından durumu createStore'nin redux işlevine geçiren bir işlev oluşturun.

 const store = createStore(appReducers, state);

2- Durum değişikliklerini dinleyin ve durum her değiştiğinde durumu şuraya kaydedin: localStorage

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

Ve işte bu ... Aslında üretimde benzer bir şey kullanıyorum, ancak fonksiyonları kullanmak yerine, aşağıdaki gibi çok basit bir sınıf yazdım ...

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
            }
        };
    }
}

ve sonra uygulamanızı önyüklerken ...

import StateLoader from "./state.loader"

const stateLoader = new StateLoader();

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

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

Umarım birine yardımcı olur

Performans Notu

Uygulamanızda durum değişiklikleri çok sık oluyorsa, yerel depolamaya çok sık kaydetme, özellikle serileştirme / seriyi kaldırma durum nesnesi grafiği büyükse, uygulamanızın performansına zarar verebilir. Bu gibi durumlar için, sen gürültüye istediğiniz veya kullanarak localStorage için durumunu kaydeder fonksiyonu azaltma olabilir RxJs, lodashya da ona benzer bir şey.


11
Ara yazılım kullanmak yerine bu yaklaşımı tercih ediyorum. Performans endişeleriyle ilgili ipuçları için teşekkürler.
Joe zhou

1
Kesinlikle tercih edilen cevap. Bununla birlikte, sayfayı yenilediğimde ve durumu yerel depodan depoyu oluştururken yüklediğinde, indirgeyici tarafından alınan önceki durumda bulunan "Beklenmeyen özellikler [konteyner adları] metnini içeren birkaç uyarı alıyorum. Şunlardan birini bulmam bekleniyor bunun yerine bilinen indirgeyici özellik adları: "global", "dil". Beklenmeyen özellikler göz ardı edilecek. Hala çalışıyor ve temelde mağazayı yaratma noktasında diğer tüm kapsayıcıları bilmediğinden şikayet ediyor. bu uyarıyı
aşmanın

@Zief söylemesi zor. Mesaj oldukça açık "görünüyor", redüktörler belirtilmemiş özellikler bekliyorlar. Serileştirilmiş duruma varsayılan değerler sağlamakla ilgili bir şey olabilir mi?
Aslan

Çok basit çözüm. Teşekkür ederim.
Ishara Madawa

1
@ Joezhou, bu yaklaşımı neden tercih ettiğinizi duymak ister. Şahsen bu, ara yazılımın amaçlandığı şey gibi görünüyor.
michaelgmcd

1

Bu, Leo'nun cevabına dayanmaktadır (herhangi bir üçüncü şahıs kitaplığı kullanmadan sorunun amacına ulaştığı için kabul edilen cevap olmalıdır).

Bir Redux Mağazası oluşturan, yerel depolamayı kullanarak devam ettiren ve bir alıcı aracılığıyla mağazasına basit erişim sağlayan bir Singleton sınıfı oluşturdum .

Kullanmak için, aşağıdaki Redux-Provider öğesini ana sınıfınızın etrafına koyun:

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

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

ve aşağıdaki sınıfı projenize ekleyin:

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;

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.