Redux mağazasının durumu nasıl sıfırlanır?


455

Devlet yönetimi için Redux kullanıyorum.
Mağazayı başlangıç ​​durumuna nasıl sıfırlarım?

Örneğin, iki kullanıcı hesabım ( u1ve u2) olduğunu varsayalım .
Aşağıdaki olay sırasını düşünün:

  1. Kullanıcı u1uygulamada oturum açar ve bir şey yapar, böylece mağazadaki bazı verileri önbelleğe alırız.

  2. Kullanıcı u1oturumu kapatır.

  3. Kullanıcı u2, tarayıcıyı yenilemeden uygulamaya giriş yapar.

Bu noktada, önbelleğe alınan verilerle ilişkilendirilir u1ve temizlemek istiyorum.

İlk kullanıcı oturumu kapattığında Redux deposunu ilk durumuna nasıl sıfırlayabilirim?


8
Muhtemelen çıkışta devleti temizlemek daha iyidir (güvenlik açısından)
Clarkie

Yanıtlar:


1034

Bunu yapmanın bir yolu, uygulamanıza bir kök düşürücü yazmak olacaktır.

Kök azaltıcı normalde eylemin işleme tarafından oluşturulan azaltıcıya devreder combineReducers(). Ancak, ne zamanUSER_LOGOUT işlem , başlangıç ​​durumunu tekrar tekrar döndürür.

Örneğin, kök düşürücünüz şöyle görünüyorsa:

const rootReducer = combineReducers({
  /* your app’s top-level reducers */
})

Yeniden adlandırabilir appReducerve yeni bir rootReducertemsilci yazabilirsiniz :

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  return appReducer(state, action)
}

Şimdi sadece yenisine eylemden rootReducersonra başlangıç ​​durumuna dönmeyi öğretmeliyiz USER_LOGOUT. Bildiğimiz gibi, indirgeyicilerin undefined, eylem ne olursa olsun, ilk argüman olarak çağrıldıklarında başlangıç ​​durumuna dönmeleri beklenir . Diyelim şartlı biriken şerit bu gerçeği kullanın statebiz bunu geçerken appReducer:

 const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

Şimdi, her USER_LOGOUTateşlendiğinde, tüm redüktörler yeniden başlatılacak. Ayrıca, istedikleri takdirde başlangıçta yaptıklarıdan farklı bir şey iade edebilirler, çünkü kontrol edebilirler action.type.

Tekrarlamak için, yeni kodun tamamı şöyle görünür:

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

Burada durumu mutasyona uğratmadığımı, sadece yerel bir değişkenin referansını yeniden atarımstate başka bir işleve geçmeden önce . Bir devlet nesnesini değiştirmek, Redux ilkelerinin ihlali anlamına gelir.

Redux-persist kullanıyorsanız , depolama alanınızı da temizlemeniz gerekebilir. Redux-persist, durumunuzun bir kopyasını bir depolama motorunda tutar ve durum kopyası yenileme sırasında oradan yüklenir.

İlk olarak, uygun depolama motorunu içe aktarmanız ve ardından undefinedher depolama durumu anahtarına ayarlamadan önce durumu ayrıştırmanız ve temizlemeniz gerekir.

const rootReducer = (state, action) => {
    if (action.type === SIGNOUT_REQUEST) {
        // for all keys defined in your persistConfig(s)
        storage.removeItem('persist:root')
        // storage.removeItem('persist:otherKey')

        state = undefined;
    }
    return appReducer(state, action);
};

15
Merak ediyorum Dan, redüktörünüzde böyle bir şey yapabilir misiniz? CLEAR_DATA eylemdir. case 'CLEAR_DATA': return initialState
HussienK

6
@HussienK bu işe yarar ancak her redüktör için devlet üzerinde çalışmaz.
Cory Danielson

12
İşte asenkron redüktörleri kullanmanız durumunda redüktörleri dinamik olarak birleştirdiğiniz bir versiyon:export const createRootReducer = asyncReducers => { const appReducer = combineReducers({ myReducer ...asyncReducers }); return (state, action) => { if (action.type === 'LOGOUT_USER') { state = undefined; } return appReducer(state, action); } };
Ivo Sabev

2
if (action.type === 'RESET') return action.stateFromLocalStorage
Dan Abramov

3
Bu yaklaşım devleti ve tüm tarihini tamamen temizliyor mu? Güvenlik açısından düşünüyorum: Bu uygulanmışsa, USER_LOGOUTeylem başlatıldıktan sonra, daha sonradan durum verileri elde etmek mümkün müdür? (örn. devtools aracılığıyla)
AlexKempton

81

Tepki-yönlendirici-redux paketini bu yaklaşımla birlikte kullanırken garip bir sorun yaşadığımız hariç, Dan Abramov tarafından kabul edilen yorumun doğru olduğunu belirtmek isterim. Düzeltmemiz, durumu undefinedgeçerli yönlendirme redüktörüne ayarlamak değil, yine de kullanmaktı. Bu paketi kullanıyorsanız aşağıdaki çözümü uygulamanızı öneririm

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    const { routing } = state
    state = { routing } 
  }
  return appReducer(state, action)
}

19
Buradaki paketin, çıkışta tüm durum ağacını temizlemek istemeyeceğinizi düşünüyorum - yaklaşım, herhangi bir alt ağacın kök azaltıcısında eşit derecede iyi çalışır ve bu nedenle bu tekniği yalnızca alt ağaç (ler) yok 'special' çocuklara seçmek dışarı ziyade, temizlemek istediğiniz değil , bunun gibi bütün ağacın kök redüktör net
davnicwil

1
Sanırım şu anda atıfta bulunduğunuz bu sorunları yaşıyorum, (oturumdan çıkıldığında doğru yolu seçecek, ancak tam bir farklı bileşen yükleyecek), düzeltmek için sizinkine benzer bir şey uyguladım, ancak bir şey düşünüyorum değişmez js bunu topluyor. RESET-STATE eylemine sahip bir üst redüktör oluşturdum ve yönlendirmeye tamamen dokunmaktan kaçınmak için bu redüktörden miras kaldım
Neta Meta

Benzer sorunlar yaşıyordum, bu sorunu çözdü. Teşekkürler.
Lloyd Watkin

3
routerrounting
Reat

2
@Mrchief cevabınızdaki gibi tanımladığınıza göre değişir combineReducers()..... eğer combineReducers({routing: routingReducer})cevabınızda anlatıldığı gibi olsaydı
Ben Lonsdale

40

Bir eylem tanımlayın:

const RESET_ACTION = {
  type: "RESET"
}

Sonra her bir redüktörde birden fazla işlemi kullandığınızı switchveya kullandığınız varsayılarak if-elseredüktörlerinizin her birinde. Davayı a switch.

const INITIAL_STATE = {
  loggedIn: true
}

const randomReducer = (state=INITIAL_STATE, action) {
  switch(action.type) {
    case 'SOME_ACTION_TYPE':

       //do something with it

    case "RESET":

      return INITIAL_STATE; //Always return the initial state

   default: 
      return state; 
  }
}

Bu şekilde her aradığınızda RESET , eylemi çağırışınızda, indirgeyici depoyu varsayılan durumla güncelleyecektir.

Şimdi, çıkış için aşağıdaki gibi işlem yapabilirsiniz:

const logoutHandler = () => {
    store.dispatch(RESET_ACTION)
    // Also the custom logic like for the rest of the logout handler
}

Bir kullanıcı her oturum açtığında, tarayıcı yenilemeden. Mağaza her zaman varsayılan olarak olacaktır.

store.dispatch(RESET_ACTION)sadece fikri detaylandırıyor. Büyük olasılıkla bu amaçla bir eylem oluşturucunuz olacaktır. Çok daha iyi bir yol,LOGOUT_ACTION .

Bunu gönderdikten sonra LOGOUT_ACTION. Özel bir ara katman yazılımı bu eylemi Redux-Saga veya Redux-Thunk ile kesebilir. Ancak her iki yönde de başka bir 'RESET' eylemi gönderebilirsiniz. Bu şekilde mağaza oturumunu kapatma ve sıfırlama aynı anda gerçekleşecek ve mağazanız başka bir kullanıcı girişi için hazır olacaktır.


1
Ben bu sadece undefineddiğer cevap gibi devlet ayarlamak daha iyi bir yaklaşım gibi hissediyorum . uygulamanız bir devlet ağacı beklerken ve bunun undefinedyerine onu verdiğinizde , başa çıkmak için sadece boş bir ağaçtan daha fazla böcek ve baş ağrısı vardır.
worc

3
@worc Eyalet aslında tanımsız olmayacak, çünkü redüktörler tanımsız bir durum aldıklarında initialState'e geri dönüyor
Guillaume

3
@worc, bu yaklaşımla, herkes yeni bir redüktör oluşturduğunda, sıfırlama durumunu eklemeyi hatırlamanız gerektiğini düşünür.
Francute

1
kesinlikle bu konuda fikrimi değiştirdim, her iki nedenle de artı RESET_ACTION bir eylem olduğu fikri . bu yüzden başlangıçta redüktöre ait değildir.
worc

1
Bu kesinlikle doğru yaklaşım. Devleti Başlangıç ​​Devletinden başka bir şeye ayarlamak sadece sorun istiyor
Sebastian Serrano

15

En iyi cevaba basitleştirilmiş bir cevap:

const rootReducer = combineReducers({
    auth: authReducer,
    ...formReducers,
    routing
});


export default (state, action) =>
  rootReducer(action.type === 'USER_LOGOUT' ? undefined : state, action);

Bu işe yarıyor teşekkürler, Dan'ın cevabından geldim ama anlayamıyorum.
Aljohn Yamaro

14
 const reducer = (state = initialState, { type, payload }) => {

   switch (type) {
      case RESET_STORE: {
        state = initialState
      }
        break
   }

   return state
 }

Ayrıca ilk depoya sıfırlamak istediğiniz tüm veya bazı redüktörlerin işlediği bir eylemi de başlatabilirsiniz. Bir eylem tüm durumunuzu sıfırlayabilir veya yalnızca sizin için uygun görünen bir parçasını tetikleyebilir. Bunun bunu yapmanın en basit ve en kontrol edilebilir yolu olduğuna inanıyorum.


10

Redux ile aşağıdaki çözümü uyguladıysanız, tüm redüktörlerimde bir initialState ayarladığımı varsayar (örn. {User: {name, email}}). Birçok bileşende bu yuvalanmış özellikleri kontrol ediyorum, bu nedenle bu düzeltme ile render yöntemlerimin birleştirilmiş özellik koşullarında kırılmasını önlüyorum (örn. State.user.email, eğer bir hata atacak olan kullanıcı yukarıda belirtilen çözümler tanımsızsa).

const appReducer = combineReducers({
  tabs,
  user
})

const initialState = appReducer({}, {})

const rootReducer = (state, action) => {
  if (action.type === 'LOG_OUT') {
    state = initialState
  }

  return appReducer(state, action)
}

7

GÜNCELLEME NGRX4

NGRX 4'e geçiş yapıyorsanız, taşıma kılavuzundan fark etmiş olabilirsiniz yapıyorsanız redüktörlerinizi birleştirmek için kök indirgeme yönteminin yerine ActionReducerMap yönteminin getirildiğini . İlk başta, işleri yapmanın bu yeni yolu, sıfırlama durumunu bir meydan okuma haline getirebilir. Aslında çok basit, ama bunu yapmanın yolu değişti.

Bu çözüm, NGRX4 Github belgelerinin meta-redüktörler API bölümünden esinlenmiştir.

İlk olarak, NGRX'in yeni ActionReducerMap seçeneğini kullanarak redüktörlerinizi böyle birleştirdiğinizi varsayalım:

//index.reducer.ts
export const reducers: ActionReducerMap<State> = {
    auth: fromAuth.reducer,
    layout: fromLayout.reducer,
    users: fromUsers.reducer,
    networks: fromNetworks.reducer,
    routingDisplay: fromRoutingDisplay.reducer,
    routing: fromRouting.reducer,
    routes: fromRoutes.reducer,
    routesFilter: fromRoutesFilter.reducer,
    params: fromParams.reducer
}

Şimdi, durumu uygulama içinden sıfırlamak istediğinizi varsayalım. Modül `

//app.module.ts
import { IndexReducer } from './index.reducer';
import { StoreModule, ActionReducer, MetaReducer } from '@ngrx/store';
...
export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
    return function(state, action) {

      switch (action.type) {
          case fromAuth.LOGOUT:
            console.log("logout action");
            state = undefined;
      }

      return reducer(state, action);
    }
  }

  export const metaReducers: MetaReducer<any>[] = [debug];

  @NgModule({
    imports: [
        ...
        StoreModule.forRoot(reducers, { metaReducers}),
        ...
    ]
})

export class AppModule { }

'

Ve bu NGRX 4 ile aynı etkiyi elde etmenin bir yoludur.


5

Dan, Ryan ve Rob'un, routerdevleti korumak ve eyalet ağacındaki her şeyi başlatmak için yaklaşımlarını birleştirerek, bununla sonuçlandım:

const rootReducer = (state, action) => appReducer(action.type === LOGOUT ? {
    ...appReducer({}, {}),
    router: state && state.router || {}
  } : state, action);

4

Redux'a durumu sıfırlama yeteneği vermek için bir bileşen oluşturdum, sadece mağazanızı geliştirmek ve belirli bir eylemi göndermek için bu bileşeni kullanmanız gerekir. Sıfırlamayı tetiklemek için. Uygulama düşüncesi @Dan Abramov'un söyledikleriyle aynı.

Github: https://github.com/wwayne/redux-reset


4

Durumu temizlemek için eylemler yarattım. Bir çıkış eylemi yaratıcısı gönderdiğimde, aynı zamanda durumu netleştirmek için eylemler gönderirim.

Kullanıcı kaydı işlemi

export const clearUserRecord = () => ({
  type: CLEAR_USER_RECORD
});

Çıkış eylemi oluşturucu

export const logoutUser = () => {
  return dispatch => {
    dispatch(requestLogout())
    dispatch(receiveLogout())
    localStorage.removeItem('auth_token')
    dispatch({ type: 'CLEAR_USER_RECORD' })
  }
};

redüktör

const userRecords = (state = {isFetching: false,
  userRecord: [], message: ''}, action) => {
  switch (action.type) {
    case REQUEST_USER_RECORD:
    return { ...state,
      isFetching: true}
    case RECEIVE_USER_RECORD:
    return { ...state,
      isFetching: false,
      userRecord: action.user_record}
    case USER_RECORD_ERROR:
    return { ...state,
      isFetching: false,
      message: action.message}
    case CLEAR_USER_RECORD:
    return {...state,
      isFetching: false,
      message: '',
      userRecord: []}
    default:
      return state
  }
};

Bunun en uygun olup olmadığından emin değilim?


2

Eğer kullanıyorsanız redux-eylemler , burada HOF (kullanarak hızlı bir çözüm var Higher Sıra Fonksiyon ) için handleActions.

import { handleActions } from 'redux-actions';

export function handleActionsEx(reducer, initialState) {
  const enhancedReducer = {
    ...reducer,
    RESET: () => initialState
  };
  return handleActions(enhancedReducer, initialState);
}

Ve sonra redüktörleri işlemek için handleActionsExorijinal yerine kullanın handleActions.

Dan'ın cevabı bu sorun hakkında harika bir fikir veriyor, ama benim için iyi sonuç vermedi, çünkü kullanıyorum redux-persist.
İle birlikte kullanıldığında redux-persist, sadece geçiş undefineddurumu kalıcı davranışı tetiklemedi, bu yüzden öğeyi depodan manuel olarak kaldırmak zorunda olduğumu biliyordum (benim durumumda React, bu nedenle AsyncStorage).

await AsyncStorage.removeItem('persist:root');

veya

await persistor.flush(); // or await persistor.purge();

benim için de çalışmadı - sadece bana bağırdılar. (örneğin, "Beklenmedik anahtar _persist ..." gibi şikayetçi )

Sonra aniden istediğim her şeyi düşündüm, sadece her bir redüktörün RESETeylem tipi ile karşılaşıldığında kendi başlangıç ​​durumuna dönmesini sağlamak . Bu şekilde, ısrar doğal olarak ele alınır. Açıkçası yukarıdaki yarar fonksiyonu ( handleActionsEx) olmadan , benim kod DRY görünmüyor (her ne kadar sadece bir astar, yani RESET: () => initialState), ama dayanamadım çünkü metaprogramming seviyorum.


2

Aşağıdaki çözüm benim için çalıştı.

Meta redüktörlere sıfırlama durumu fonksiyonu ekledim.

return reducer(undefined, action);

tüm redüktörleri başlangıç ​​durumuna getirmek için. undefinedBunun yerine geri dönmek , mağazanın yapısının tahrip olması nedeniyle hatalara neden oluyordu.

/reducers/index.ts

export function resetState(reducer: ActionReducer<State>): ActionReducer<State> {
  return function (state: State, action: Action): State {

    switch (action.type) {
      case AuthActionTypes.Logout: {
        return reducer(undefined, action);
      }
      default: {
        return reducer(state, action);
      }
    }
  };
}

export const metaReducers: MetaReducer<State>[] = [ resetState ];

app.module.ts

import { StoreModule } from '@ngrx/store';
import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, { metaReducers })
  ]
})
export class AppModule {}

2

Güvenlik açısından bakıldığında, en güvenli şey, bir kullanıcı out giriş tüm kalıcı durumunu sıfırlamak için zaman yapmak (ex kurabiye, için localStorage, IndexedDB, Web SQL, vs) kullanarak sayfanın tamamen yenilemeniz window.location.reload(). Özensiz bir geliştiricinin kazayla veya kasıtlı olarak bazı hassas verileri windowDOM'da vb. Saklaması mümkündür. Tüm kalıcı durumları havaya uçurmak ve tarayıcıyı yenilemek, önceki kullanıcıdan hiçbir bilginin bir sonraki kullanıcıya sızmamasını garanti etmenin tek yoludur.

(Elbette, paylaşılan bir bilgisayardaki bir kullanıcı olarak "özel tarama" modunu kullanmalı, tarayıcı penceresini kendiniz kapatmalı, "tarama verilerini temizle" işlevini vb. Kullanmalısınız, ancak bir geliştirici olarak herkesin her zaman çalışkan)


1
İnsanlar neden bunu düşürdü? Boş içeriğe sahip yeni bir redux durumu yaptığınızda, temel olarak bellekte önceki durumlara sahip olursunuz ve teorik olarak bunlardan verilere erişebilirsiniz. Tarayıcıyı yenilemek en güvenli bahistir!
Wilhelm Sorban

2

Dan'ın cevabının üstüne inşa edilen daktilo ile çalışırken geçici çözümüm (redux yazımları undefined, ilk argüman olarak redüktöre geçmeyi imkansız hale getirir , bu nedenle ilk kök durumunu sabit olarak önbelleğe alırım ):

// store

export const store: Store<IStoreState> = createStore(
  rootReducer,
  storeEnhacer,
)

export const initialRootState = {
  ...store.getState(),
}

// root reducer

const appReducer = combineReducers<IStoreState>(reducers)

export const rootReducer = (state: IStoreState, action: IAction<any>) => {
  if (action.type === "USER_LOGOUT") {
    return appReducer(initialRootState, action)
  }

  return appReducer(state, action)
}


// auth service

class Auth {
  ...

  logout() {
    store.dispatch({type: "USER_LOGOUT"})
  }
}

2

Kabul edilen cevap davamı çözmeme yardımcı oldu. Ancak, bütün devletin temizlenmemesi gereken bir olayla karşılaştım. Yani - bu şekilde yaptım:

const combinedReducer = combineReducers({
    // my reducers 
});

const rootReducer = (state, action) => {
    if (action.type === RESET_REDUX_STATE) {
        // clear everything but keep the stuff we want to be preserved ..
        delete state.something;
        delete state.anotherThing;
    }
    return combinedReducer(state, action);
}

export default rootReducer;

Umarım bu başka birine yardımcı olur :)


10'dan fazla durumum varsa ancak yalnızca bir redüktörün durumunu sıfırlamak istersem ne olur?
Paul

1

Sadece @ dan-abramov cevabının bir uzantısıdır , bazen belirli anahtarların sıfırlanmasını engellememiz gerekebilir.

const retainKeys = ['appConfig'];

const rootReducer = (state, action) => {
  if (action.type === 'LOGOUT_USER_SUCCESS' && state) {
    state = !isEmpty(retainKeys) ? pick(state, retainKeys) : undefined;
  }

  return appReducer(state, action);
};

1

Benim için çalışan hızlı ve kolay bir seçenek redux-reset kullanıyordu . Bu daha basit ve daha büyük uygulamalar için bazı gelişmiş seçeneklere sahip.

Oluşturma deposunda kurulum

import reduxReset from 'redux-reset'
...
const enHanceCreateStore = compose(
applyMiddleware(...),
reduxReset()  // Will use 'RESET' as default action.type to trigger reset
)(createStore)
const store = enHanceCreateStore(reducers)

Çıkış işlevinizde 'sıfırla' öğenizi gönderin

store.dispatch({
type: 'RESET'
})

Bu yardımcı olur umarım


1

Redux'un ilk durumun aynı değişkenine başvurmasını önlemek için benim almam:

// write the default state as a function
const defaultOptionsState = () => ({
  option1: '',
  option2: 42,
});

const initialState = {
  options: defaultOptionsState() // invoke it in your initial state
};

export default (state = initialState, action) => {

  switch (action.type) {

    case RESET_OPTIONS:
    return {
      ...state,
      options: defaultOptionsState() // invoke the default function to reset this part of the state
    };

    default:
    return state;
  }
};

Varsayılan durumu bir işlev olarak yazma fikri, günü gerçekten kurtardı. Teşekkür ederim
Chris

0

Bu yaklaşım çok doğru: Başkalarını göz ardı etmek ve korumak için belirli bir "NAME" durumunu yok edin.

const rootReducer = (state, action) => {
    if (action.type === 'USER_LOGOUT') {
        state.NAME = undefined
    }
    return appReducer(state, action)
}

Durum ağacınızın yalnızca bir parçasını sıfırlamanız gerekirse USER_LOGOUT, bu redüktörü de dinleyebilir ve orada tutabilirsiniz .
Andy_D

0

neden sadece kullanmıyorsun return module.exports.default();)

export default (state = {pending: false, error: null}, action = {}) => {
    switch (action.type) {
        case "RESET_POST":
            return module.exports.default();
        case "SEND_POST_PENDING":
            return {...state, pending: true, error: null};
        // ....
    }
    return state;
}

Not: eylem varsayılan değerini ayarladığınızdan emin olun {}ve tamamsınız çünkü action.typeanahtar deyimini kontrol ettiğinizde hatayla karşılaşmak istemezsiniz .


0

Kabul edilen cevabın benim için iyi çalıştığını buldum, ancak ESLint no-param-reassignhatasını tetikledi - https://eslint.org/docs/rules/no-param-reassign

Bunun yerine, şu şekilde ele aldım, devletin bir kopyasını oluşturduğumdan emin olun (ki bu benim anlayışımla yapılacak Reduxy şeyidir ...):

import { combineReducers } from "redux"
import { routerReducer } from "react-router-redux"
import ws from "reducers/ws"
import session from "reducers/session"
import app from "reducers/app"

const appReducer = combineReducers({
    "routing": routerReducer,
    ws,
    session,
    app
})

export default (state, action) => {
    const stateCopy = action.type === "LOGOUT" ? undefined : { ...state }
    return appReducer(stateCopy, action)
}

Ama belki devletin bir kopyasını oluşturmak, onu biraz fazla karmaşık olan bir kopyasını oluşturan başka bir redüktör işlevine geçirmek için mi? Bu iyi okunmuyor, ancak daha da önemlisi:

export default (state, action) => {
    return appReducer(action.type === "LOGOUT" ? undefined : state, action)
}

0

Dan Abramov'un cevabına ek olarak, eylemi açıkça state = undefined ile birlikte action = {type: '@@ INIT'} olarak ayarlamamalıyız. Yukarıdaki eylem türünde, her redüktör başlangıç ​​durumunu döndürür.


0

sunucuda, bir değişken var: global.isSsr = true ve her redüktörde, bir const var: initialState Mağazadaki verileri sıfırlamak için, her Reducer ile aşağıdakileri yaparım : appReducer.js ile örnek :

 const initialState = {
    auth: {},
    theme: {},
    sidebar: {},
    lsFanpage: {},
    lsChatApp: {},
    appSelected: {},
};

export default function (state = initialState, action) {
    if (typeof isSsr!=="undefined" && isSsr) { //<== using global.isSsr = true
        state = {...initialState};//<= important "will reset the data every time there is a request from the client to the server"
    }
    switch (action.type) {
        //...other code case here
        default: {
            return state;
        }
    }
}

son olarak sunucunun yönlendiricisinde:

router.get('*', (req, res) => {
        store.dispatch({type:'reset-all-blabla'});//<= unlike any action.type // i use Math.random()
        // code ....render ssr here
});

0

Aşağıdaki çözüm benim için çalışıyor.

İlk üzerindeki başlatılması bizim uygulamanın redüktör durumudur taze ve yeni varsayılan ile InitialState .

Varsayılan durumuna devam etmek için APP başlangıç ​​yükünü çağıran bir eylem eklemeliyiz .

Uygulamadan çıkış yaparken , varsayılan durumu basitçe yeniden atayabilir ve redüktör yeni gibi çalışacaktır .

Ana APP Kabı

  componentDidMount() {   
    this.props.persistReducerState();
  }

Ana APP Redüktör

const appReducer = combineReducers({
  user: userStatusReducer,     
  analysis: analysisReducer,
  incentives: incentivesReducer
});

let defaultState = null;
export default (state, action) => {
  switch (action.type) {
    case appActions.ON_APP_LOAD:
      defaultState = defaultState || state;
      break;
    case userLoginActions.USER_LOGOUT:
      state = defaultState;
      return state;
    default:
      break;
  }
  return appReducer(state, action);
};

Durumu sıfırlamak için Oturum kapatma çağrısı eylemi hakkında

function* logoutUser(action) {
  try {
    const response = yield call(UserLoginService.logout);
    yield put(LoginActions.logoutSuccess());
  } catch (error) {
    toast.error(error.message, {
      position: toast.POSITION.TOP_RIGHT
    });
  }
}

Umarız bu sorununuzu çözer!


0

Durumu ilk durumuna sıfırlamak için, aşağıdaki kodu yazdım:

const appReducers = (state, action) =>
   combineReducers({ reducer1, reducer2, user })(
     action.type === "LOGOUT" ? undefined : state,
     action
);

0

Kabul edilen cevaptaki çözümün yapmadığı bir şey, parametreli seçiciler için önbelleği temizlemektir. Böyle bir seçiciniz varsa:

export const selectCounter1 = (state: State) => state.counter1;
export const selectCounter2 = (state: State) => state.counter2;
export const selectTotal = createSelector(
  selectCounter1,
  selectCounter2,
  (counter1, counter2) => counter1 + counter2
);

O zaman bunları çıkışta şu şekilde serbest bırakmanız gerekir:

selectTotal.release();

Aksi takdirde, seçicinin son çağrısının kaydedilen değeri ve son parametrelerin değerleri hala bellekte kalır.

Kod örnekleri ngrx belgelerinden alınmıştır .


0

benim için en uygun olanı initialStatebunun yerine koymaktır state:

  const reducer = createReducer(initialState,
  on(proofActions.cleanAdditionalInsuredState, (state, action) => ({
    ...initialState
  })),

-1

Başka bir seçenek:

store.dispatch({type: '@@redux/INIT'})

'@@redux/INIT'redux'un siz otomatik olarak gönderdiği eylem türüdür createStore, bu nedenle redüktörlerinizin zaten bir varsayılanı varsayarsak, bu olanlar tarafından yakalanır ve durumunuzu yeni başlatacaktır. Yine de redux'un özel bir uygulama detayı olarak düşünülebilir, bu yüzden alıcı dikkat edin ...


Durum değiştirmediğini yaptım, ayrıca ReduxDevtools'ta ilk eylem olarak gösterilen @@ INIT'i denedim
Reza

-2

Oturumu kapat bağlantısının oturumu temizlemesini ve sayfayı yenilemesini sağlamanız yeterlidir. Mağazanız için ek kod gerekmez. Durumu tamamen sıfırlamak istediğinizde, sayfa yenilemesi bunu işlemenin basit ve kolayca tekrarlanabilir bir yoludur.


1
Mağazayı localstorage ile senkronize eden bir ara katman yazılımı kullanırsanız ne olur? O zaman yaklaşımınız işe yaramıyor ...
Spock

8
İnsanların neden böyle cevapları neden küçümsediğini gerçekten anlamıyorum.
Wylliam Judd

İnsanlar neden bunu düşürdü? Boş içeriğe sahip yeni bir redux durumu yaptığınızda, temel olarak bellekte önceki durumlara sahip olursunuz ve teorik olarak bunlardan verilere erişebilirsiniz. Tarayıcıyı yenilemek en güvenli bahistir!
Wilhelm Sorban

-3

onLogout() {
  this.props.history.push('/login'); // send user to login page
  window.location.reload(); // refresh the page
}


açıklamak? @SinanSamet
Nikita Beznosikov

Açık olmak gerekirse ben oy vermedim. Ama cesaretini kırıyorum. Giriş ve yeniden yükleme için giderseniz, muhtemelen evet oturumunu kapatırsınız. Ama sadece devletini kaybettiğin için. Redux-persist kullanmadığınız sürece bu durumda oturumu kapatmazsınız. Genel olarak, sadece işlevleri görmekten nefret ediyorumwindow.location.reload();
Sinan Samet

- Bunun gibi işlevler yazmayın. - Neden? - Sevmiyorum.
Nikita Beznosikov

1
Sayfayı yeniden yüklemek, mağaza durumunu sıfırlamaktan farklıdır. Ayrıca, windowtepki göstermeyen bir ortamda olabilirsiniz
Max
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.