Redux स्टोर की स्थिति को कैसे रीसेट करें?


455

मैं राज्य प्रबंधन के लिए Redux का उपयोग कर रहा हूं।
मैं स्टोर को उसकी प्रारंभिक स्थिति में कैसे रीसेट करूं?

उदाहरण के लिए, मान लें कि मेरे दो उपयोगकर्ता खाते हैं ( u1और u2)।
घटनाओं के निम्नलिखित अनुक्रम की कल्पना करें:

  1. उपयोगकर्ता u1ऐप में लॉग इन करता है और कुछ करता है, इसलिए हम स्टोर में कुछ डेटा कैश करते हैं।

  2. उपयोगकर्ता u1लॉग आउट करता है।

  3. उपयोगकर्ता u2ब्राउज़र को ताज़ा किए बिना ऐप में लॉग इन करता है।

इस बिंदु पर, कैश्ड डेटा के साथ संबद्ध किया जाएगा u1, और मैं इसे साफ करना चाहूंगा।

जब पहला उपयोगकर्ता लॉग आउट करता है तो मैं Redux स्टोर को उसकी प्रारंभिक स्थिति में कैसे रीसेट कर सकता हूं?


8
संभवतः लॉगआउट पर राज्य को खाली करना बेहतर है (सुरक्षा दृष्टिकोण से)
क्लर्की

जवाबों:


1033

ऐसा करने का एक तरीका यह होगा कि आप अपने आवेदन में एक रूट रिड्यूसर लिखें।

रूट reducer आमतौर पर उत्पन्न reducer के लिए कार्रवाई से निपटने प्रतिनिधि होगा combineReducers()। हालाँकि, जब भी यह प्राप्त होता हैUSER_LOGOUT कार्रवाई है, यह प्रारंभिक अवस्था को फिर से लौटा देता है।

उदाहरण के लिए, यदि आपका रूट reducer इस तरह दिखता है:

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

आप इसका नाम बदलकर appReducerनया rootReducerप्रतिनिधि लिख सकते हैं:

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

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

अब हमें कार्रवाई के rootReducerबाद प्रारंभिक अवस्था में लौटने के लिए नए को सिखाने की जरूरत है USER_LOGOUT। जैसा कि हम जानते हैं, रिड्यूसर प्रारंभिक स्थिति को वापस करने वाले होते हैं, जब उन्हें undefinedपहले तर्क के रूप में बुलाया जाता है, कोई फर्क नहीं पड़ता। इस तथ्य का उपयोग सशर्त stateरूप से संचित करने के लिए करते हैं क्योंकि हम इसे पास करते हैं appReducer:

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

  return appReducer(state, action)
}

अब, जब भी USER_LOGOUTआग लगती है, सभी reducers को नए सिरे से शुरू किया जाएगा। वे शुरू में किए गए काम से कुछ अलग कर सकते हैं यदि वे चाहते हैं क्योंकि वे भी जाँच कर सकते हैं action.type

दोबारा दोहराने के लिए, पूरा नया कोड इस तरह दिखता है:

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

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

  return appReducer(state, action)
}

ध्यान दें कि मैं यहां राज्य को उत्परिवर्तित नहीं कर रहा हूं, मैं केवल एक स्थानीय चर के संदर्भ को पुन: असाइन कर रहा हूं जिसे कहा जाता हैstate किसी अन्य फ़ंक्शन में पास करने से पहले । राज्य वस्तु को म्यूट करना Redux सिद्धांतों का उल्लंघन होगा।

यदि आप Redux-persist का उपयोग कर रहे हैं , तो आपको अपने भंडारण को साफ करने की भी आवश्यकता हो सकती है। Redux-persist आपके राज्य की एक प्रति एक भंडारण इंजन में रखता है, और राज्य की प्रति वहां से ताज़ा करने पर लोड की जाएगी।

सबसे पहले, आपको उचित भंडारण इंजन आयात करने की आवश्यकता है और फिर, इसे undefinedस्टोर करने के लिए राज्य को पार्स करने के लिए और प्रत्येक भंडारण राज्य कुंजी को साफ करने के लिए ।

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
मैं उत्सुक हूँ डैन, क्या आप भी अपने reducer में ऐसा कुछ कर सकते हैं। CLEAR_DATA की कार्रवाई होने के साथ। case 'CLEAR_DATA': return initialState
हुसैनक

6
@HussienK जो काम करेगा, लेकिन राज्य के लिए हर reducer के लिए नहीं।
कोरी डेनियलसन

12
यहाँ एक संस्करण है जहाँ आप डायनामिक रूप से संयोजन के मामले में reducers का उपयोग करते हैं: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
दान अब्रामोव

3
क्या यह दृष्टिकोण राज्य और उसके सभी इतिहास को पूरी तरह से स्पष्ट करता है? मैं सुरक्षा के नजरिए से सोच रहा हूं: यदि इसे लागू कर दिया गया है, तो एक बार USER_LOGOUTकार्रवाई की गई है, क्या पहले से राज्य डेटा प्राप्त करना संभव है? (उदा। देवतुलों के माध्यम से)
एलेक्सकेम्पटन २०'१ools

81

मैं यह बताना चाहूंगा कि डैन अब्रामोव द्वारा स्वीकार की गई टिप्पणी सही है, सिवाय इसके कि जब हमने इस दृष्टिकोण के साथ प्रतिक्रिया-राउटर-रिडक्स पैकेज का उपयोग किया तो हमें एक अजीब समस्या का सामना करना पड़ा। हमारा निर्धारण राज्य को निर्धारित नहीं करना था undefined, बल्कि वर्तमान रूटिंग रेड्यूसर का उपयोग करना था। इसलिए मैं नीचे दिए गए समाधान को लागू करने का सुझाव दूंगा यदि आप इस पैकेज का उपयोग कर रहे हैं

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

19
मुझे लगता है कि यहाँ टेकअवे का मतलब यह है कि आप लॉगआउट पर पूरे राज्य के पेड़ को साफ़ नहीं करना चाहते हैं - किसी भी सबट्री के रूट रिड्यूसर पर यह दृष्टिकोण समान रूप से अच्छी तरह से काम करता है, और इसलिए इस तकनीक को केवल रूट रीड्यूसर पर लागू करना स्पष्ट हो सकता है सबट्री (रों) आप करते हैं 'विशेष' के लिए बच्चों चुनने से साफ़ करने के लिए, बल्कि चाहते हैं नहीं पूरे पेड़ की जड़ कम करने पर स्पष्ट है, इस तरह
davnicwil

1
मुझे लगता है कि मैं इस मुद्दे का अनुभव कर रहा हूं जिसे आप अभी संदर्भित कर रहे हैं, (जहां लॉगआउट पर यह रूट को सही रास्ते पर सेट करेगा लेकिन एक पूर्ण भिन्न घटक लोड होगा) मैंने इसे ठीक करने के लिए आपके समान कुछ लागू किया है, लेकिन मुझे लगता है कि कुछ के साथ अपरिवर्तनीय js यह मालिश कर रहा है। मैंने एक मूल रेड्यूसर का निर्माण किया, जिसमें RESET-STATE एक्शन है, और मुझे उस रेड्यूसर से विरासत में मिली रूटिंग को पूरी तरह से छूने से बचने के लिए
Neta Meta

समान मुद्दों का सामना कर रहा था, इसने इसे ठीक कर दिया है। धन्यवाद।
लॉयड वाटकिन

3
ध्यान दें कि अभिक्रिया-रिड्यूक्स-राउटर के साथ, संपत्ति है routerऔर नहींrounting
मृकफ

2
@ शरारत यह निर्भर करती है कि आपने इसे अपने रूप में किस रूप में परिभाषित किया है combineReducers()..... अगर आपके पास combineReducers({routing: routingReducer})यह उत्तर में वर्णित है
बेन लॉन्सडेल

40

एक क्रिया को परिभाषित करें:

const RESET_ACTION = {
  type: "RESET"
}

फिर अपने प्रत्येक reducers में यह मान कर कि आप प्रत्येक reducer के माध्यम से कई क्रियाओं का उपयोग कर रहे हैं switchया कर रहे हैं if-else। मैं एक मामले के लिए ले जा रहा हूँ 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; 
  }
}

इस तरह जब भी आप RESETकार्रवाई कहते हैं , तो आप डिफ़ॉल्ट स्थिति के साथ स्टोर को अपडेट करेंगे।

अब, लॉगआउट के लिए आप नीचे दिए गए हैंडल को संभाल सकते हैं:

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

हर बार एक उपयोगकर्ता में, एक ब्राउज़र ताज़ा किए बिना। स्टोर हमेशा डिफ़ॉल्ट पर होगा।

store.dispatch(RESET_ACTION)बस विचार विस्तृत है। आप सबसे अधिक उद्देश्य के लिए एक एक्शन क्रिएटर होंगे। एक बेहतर तरीका यह होगा कि आपके पास ए LOGOUT_ACTION

एक बार जब आप इस प्रेषण LOGOUT_ACTION। एक कस्टम मिडलवेयर तब इस क्रिया को रोक सकता है, या तो Redux-Saga या Redux-Thunk के साथ। हालाँकि, दोनों तरीके से आप एक और कार्रवाई 'RESET' भेज सकते हैं। इस तरह से स्टोर लॉगआउट और रीसेट समकालिक रूप से हो जाएगा और आपका स्टोर किसी अन्य उपयोगकर्ता लॉगिन के लिए तैयार हो जाएगा।


1
मुझे ऐसा लगता है कि यह केवल undefinedदूसरे राज्य में पसंद करने के लिए राज्य स्थापित करने से बेहतर दृष्टिकोण है । जब आपका आवेदन एक राज्य के पेड़ की उम्मीद कर रहा है और आप इसके undefinedबजाय देते हैं , तो बस एक खाली पेड़ की तुलना में अधिक कीड़े और सिरदर्द हैं।
वर्स्ट

3
@worc राज्य वास्तव में, अपरिभाषित नहीं किए जाएंगे क्योंकि reducers initialState वापसी जब वे एक अपरिभाषित राज्य प्राप्त
Guillaume

3
@ सरकार को लगता है कि इस दृष्टिकोण के साथ, हर बार जब भी कोई नया रिड्यूसर बनाता है, तो आपको रीसेट केस को जोड़ने के लिए याद रखना होगा।
फ्रांस्यूट

1
मैंने निश्चित रूप से उन दोनों कारणों से इस बारे में अपना विचार बदल दिया है, साथ ही यह विचार कि RESET_ACTION एक क्रिया है । तो यह वास्तव में reducer के साथ शुरू करने के लिए संबंधित नहीं है।
१18 ’को

1
यह निश्चित रूप से सही दृष्टिकोण है। कुछ भी करने के लिए राज्य की स्थापना, लेकिन प्रारंभिक राज्य सिर्फ मुसीबत के लिए पूछ रहा है
सेबस्टियन सेरानो

15

सबसे अच्छा जवाब के लिए एक सरलीकृत जवाब:

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


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

यह धन्यवाद काम कर रहा है, मैं डैन के जवाब से था लेकिन मैं इसका पता नहीं लगा सकता।
अल्जोन यामरो

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

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

   return state
 }

आप एक ऐसी कार्रवाई भी कर सकते हैं जो सभी या कुछ रिड्यूसर द्वारा नियंत्रित की जाती है, जिसे आप प्रारंभिक स्टोर पर रीसेट करना चाहते हैं। एक क्रिया आपके पूरे राज्य में रीसेट कर सकती है, या इसका एक टुकड़ा जो आपको उपयुक्त लगता है। मेरा मानना ​​है कि यह ऐसा करने का सबसे सरल और सबसे आसान तरीका है।


10

Redux के साथ यदि निम्नलिखित समाधान लागू किया गया है, जो मानता है कि मैंने अपने सभी रिड्यूसर (उदाहरण {उपयोगकर्ता: {नाम, ईमेल}}) में एक आरंभिक सेट निर्धारित किया है। कई घटकों में मैं इन नेस्टेड गुणों की जांच करता हूं, इसलिए इस फिक्स के साथ मैं अपने रेंडर तरीकों को रोकने के लिए युग्मित संपत्ति की शर्तों (जैसे कि state.user.email, जो एक त्रुटि उपयोगकर्ता को फेंक देगा यदि ऊपरी उल्लिखित समाधान) अपरिभाषित है, तो टूट जाता है।

const appReducer = combineReducers({
  tabs,
  user
})

const initialState = appReducer({}, {})

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

  return appReducer(state, action)
}

7

अद्यतन NGRX4

यदि आप एनजीआरएक्स 4 में माइग्रेट कर रहे हैं, तो आपने माइग्रेशन गाइड से देखा हो सकता है कि आपके रीड्यूसर के संयोजन के लिए रूट्रेडर विधि को एक्शनरेड्यूसर मैप विधि से बदल दिया गया है। सबसे पहले, चीजों को करने का यह नया तरीका रीसेट स्थिति को एक चुनौती बना सकता है। यह वास्तव में सीधे-आगे है, फिर भी ऐसा करने का तरीका बदल गया है।

यह समाधान NGRX4 Github डॉक्स के मेटा- रेड्यूसर API अनुभाग से प्रेरित है

सबसे पहले, यह बताता है कि NGRX के नए ActionReducerMap विकल्प का उपयोग करके आप अपने रीड्यूसर को इस तरह जोड़ रहे हैं:

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

अब, आपको यह बताने देता है कि आप app.module से राज्य को रीसेट करना चाहते हैं

//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 { }

`

और यह मूल रूप से NGRX 4 के साथ समान प्रभाव को प्राप्त करने का एक तरीका है।


5

डैन, रयान और रॉब के दृष्टिकोण को मिलाते हुए, routerराज्य को बनाए रखने और राज्य के पेड़ में बाकी सभी चीजों को शुरू करने के लिए, मैं इसके साथ समाप्त हुआ:

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

4

मैंने Redux को रीसेट करने की क्षमता देने के लिए एक घटक बनाया है, आपको बस अपने स्टोर को बढ़ाने और रीसेट को ट्रिगर करने के लिए एक विशेष एक्शन टाइप को भेजने के लिए इस घटक का उपयोग करने की आवश्यकता है। कार्यान्वयन का विचार वैसा ही है जैसा @ दन अब्रामोव ने कहा था।

गिथब: https://github.com/wwayne/redux-reset


4

मैंने राज्य को खाली करने के लिए कार्रवाई की है। इसलिए जब मैं एक लॉगआउट एक्शन क्रिएटर भेजता हूं तो मैं स्टेट को भी क्लियर करने के लिए एक्शन भेजता हूं।

उपयोगकर्ता रिकॉर्ड कार्रवाई

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

लॉगआउट एक्शन क्रिएटर

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

कम करने

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

मुझे यकीन नहीं है कि क्या यह इष्टतम है?


2

यदि आप रिड्यूक्स-एक्शन का उपयोग कर रहे हैं , तो इसके लिए एक HOF ( हायर ऑर्डर फंक्शन ) का उपयोग करते हुए एक त्वरित समाधान है handleActions

import { handleActions } from 'redux-actions';

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

और फिर reducers को संभालने के लिए handleActionsExमूल के बजाय का उपयोग करें handleActions

डैन का जवाब इस समस्या के बारे में एक महान विचार देता है, लेकिन यह मेरे लिए अच्छी तरह से काम नहीं करता था, क्योंकि मैं उपयोग कर रहा हूं redux-persist
जब इसके साथ प्रयोग किया जाता है redux-persist, तो बस पासिंग undefinedस्टेट ने लगातार व्यवहार को ट्रिगर नहीं किया है, इसलिए मुझे पता था कि मुझे स्टोरेज से आइटम को मैन्युअल रूप से हटाना होगा (इस मामले में रिएक्टिव नेटिव AsyncStorage)।

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

या

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

मेरे लिए भी काम नहीं किया - वे सिर्फ मुझ पर चिल्लाया। (उदाहरण के लिए, "अनपेक्षित कुंजी _पर्सिस्ट ..." जैसी शिकायत करना )

फिर मैंने अचानक सोचा था कि मैं चाहता हूं कि हर व्यक्ति रिड्यूसर को अपनी प्रारंभिक अवस्था लौटाए जब RESETकार्रवाई प्रकार का सामना करना पड़ता है। इस तरह, स्थायी रूप से प्राकृतिक रूप से संभाला जाता है। स्पष्ट रूप से उपर्युक्त उपयोगिता फ़ंक्शन ( handleActionsEx) के बिना , मेरा कोड DRY नहीं लगेगा (हालाँकि यह सिर्फ एक लाइनर है, यानी RESET: () => initialState), लेकिन मैं इसे 'cuz I love metaprogramming' नहीं कह सकता।


2

निम्नलिखित समाधान ने मेरे लिए काम किया।

मैंने मेटा रिड्यूसर्स में स्टेट फ़ंक्शन रीसेट करना जोड़ा। कुंजी का उपयोग करना था

return reducer(undefined, action);

प्रारंभिक स्थिति में सभी reducers सेट करने के लिए। undefinedइसके बजाय वापस लौटना इस तथ्य के कारण त्रुटियां पैदा कर रहा था कि स्टोर की संरचना नष्ट हो गई है।

/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

एक सुरक्षा के दृष्टिकोण से, सबसे सुरक्षित बात जब कोई उपयोगकर्ता लॉग आउट सभी लगातार राज्य पुनर्स्थापित करने के लिए है (पूर्व कुकीज़, करने के लिए localStorage, IndexedDB, Web SQL, आदि) और का उपयोग कर पृष्ठ की हार्ड ताज़ा करना window.location.reload()। यह संभव है कि एक मैला डेवलपर अकस्मात या जानबूझकर कुछ संवेदनशील डेटा को windowडोम में संग्रहीत करता है, आदि सभी निरंतर स्थिति को नष्ट कर देता है और ब्राउज़र को ताज़ा करने का एकमात्र तरीका है कि पिछले उपयोगकर्ता की कोई जानकारी अगले उपयोगकर्ता पर लीक न हो।

(बेशक, एक साझा कंप्यूटर पर एक उपयोगकर्ता के रूप में आपको "निजी ब्राउज़िंग" मोड का उपयोग करना चाहिए, ब्राउज़र विंडो को स्वयं बंद करना चाहिए, "स्पष्ट ब्राउज़िंग डेटा" फ़ंक्शन आदि का उपयोग करना चाहिए, लेकिन एक डेवलपर के रूप में हम हर किसी से हमेशा होने की उम्मीद नहीं कर सकते हैं। वह मेहनती)


1
लोगों ने इसे क्यों कम किया है? जब आप एक नया रिडक्स राज्य करते हैं, तो खाली सामग्री के साथ, आपके पास मूल रूप से अभी भी स्मृति में पिछले राज्य होते हैं, और आप सैद्धांतिक रूप से उनके साथ डेटा तक पहुंच सकते हैं। ब्राउज़र को ताज़ा करना आपकी सबसे सुरक्षित शर्त है!
विल्हेम सोरबान 17

2

टाइप के साथ काम करते समय मेरा वर्कअराउंड, डैन के उत्तर के ऊपर बनाया गया (रिडक्स टाइपिंग undefinedपहले तर्क के रूप में रिड्यूसर को पास करना असंभव बनाता है, इसलिए मैं प्रारंभिक रूट स्टेट को स्थिर रूप से कैश करता हूं):

// 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

स्वीकृत जवाब से मुझे अपना मामला सुलझाने में मदद मिली। हालाँकि, मुझे ऐसे मामले का सामना करना पड़ा जहाँ पूरे राज्य को साफ़ नहीं करना पड़ा। तो - मैंने इसे इस तरह किया:

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;

मनाइए कि यह किसी और के लिए सहायक हो :)


क्या होगा यदि मेरे पास 10 से अधिक राज्य हैं लेकिन मैं सिर्फ एक reducer की स्थिति को रीसेट करना चाहता हूं?
पॉल

1

सिर्फ @ दान-अब्रामोव जवाब के लिए एक एक्सटेंशन , कभी - कभी हमें रीसेट होने से कुछ चाबियों को बनाए रखने की आवश्यकता हो सकती है।

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

मेरे लिए काम करने वाला एक त्वरित और आसान विकल्प Redux-reset का उपयोग कर रहा था । जो सीधा था और कुछ उन्नत विकल्प भी हैं, बड़े ऐप्स के लिए।

स्टोर बनाने में सेटअप

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)

अपने लॉगआउट फ़ंक्शन में अपना 'रीसेट' डिस्पैच करें

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

उम्मीद है की यह मदद करेगा


1

Redux को प्रारंभिक अवस्था के एक ही चर के संदर्भ में रखने के लिए मेरा उपाय:

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

एक फ़ंक्शन के रूप में डिफ़ॉल्ट स्थिति को लिखने का विचार वास्तव में यहां दिन को बचाता है। धन्यवाद 8:
क्रिस पॉल

0

यह दृष्टिकोण बहुत सही है: किसी भी विशिष्ट राज्य "NAME" को अनदेखा करना और दूसरों को रखने के लिए नष्ट करना।

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

यदि आपको केवल अपने राज्य के पेड़ के एक टुकड़े को रीसेट करने की आवश्यकता है, तो आप USER_LOGOUTउस reducer के लिए भी सुन सकते हैं और इसे वहां संभाल सकते हैं।
एंडी_ डीएल

0

तुम सिर्फ इस्तेमाल क्यों नहीं करते 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;
}

नोट: सुनिश्चित करें कि आपने एक्शन डिफॉल्ट मान सेट किया है {}और आप ठीक हैं क्योंकि आप action.typeस्विच स्टेटमेंट के अंदर जांच करते समय त्रुटि का सामना नहीं करना चाहते हैं ।


0

मैंने पाया कि स्वीकृत उत्तर ने मेरे लिए अच्छा काम किया, लेकिन इसने ESLint no-param-reassignत्रुटि को ट्रिगर किया - https://eslint.org/docs/rules/no-param-reassign

यहां बताया गया है कि मैंने इसके बजाय इसे कैसे संभाला, राज्य की एक प्रति (जो मेरी समझ में है, Reduxy बात करने के लिए ...):

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

लेकिन हो सकता है कि राज्य की एक प्रति बनाने के लिए यह सिर्फ एक और reducer समारोह में पारित करने के लिए है कि एक प्रतिलिपि बनाता है एक छोटे से अधिक जटिल है? यह अच्छी तरह से पढ़ा नहीं है, लेकिन अधिक से अधिक बिंदु है:

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

0

दान अब्रामोव के जवाब के अलावा, क्या हमें स्पष्ट रूप से कार्रवाई = {प्रकार: '@@ INIT'} को राज्य = अपरिभाषित के रूप में सेट नहीं करना चाहिए। उपरोक्त क्रिया प्रकार के साथ, प्रत्येक reducer प्रारंभिक स्थिति देता है।


0

सर्वर में, मेरे पास एक वैरिएबल है: Global.isSsr = true और प्रत्येक रिड्यूसर में, मेरे पास एक कॉस्ट है: आरंभ में स्टोर में डेटा को रीसेट करने के लिए, मैं प्रत्येक Reducer के साथ निम्नलिखित कार्य करता हूं : appReducer के साथ उदाहरण ।js :

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

अंत में सर्वर के राउटर पर:

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

0

निम्नलिखित समाधान मेरे लिए काम करता है।

हमारे आवेदन की पहल पर सबसे पहले reducer राज्य ताजा है और डिफ़ॉल्ट InitialState के साथ नया है

हमें एक कार्रवाई को जोड़ना होगा जो डिफ़ॉल्ट स्थिति को बनाए रखने के लिए एपीपी इनबिल्ट लोड पर कॉल करता है ।

आवेदन से लॉग आउट जब तक हम सरल कर सकते हैं पुन: असाइन डिफ़ॉल्ट स्थिति और कम करने बस के रूप में काम करेंगे नई

मुख्य एपीपी कंटेनर

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

मुख्य एपीपी Reducer

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

राज्य को रीसेट करने के लिए लॉगआउट कॉलिंग कार्रवाई पर

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

आशा है इससे तुम्हारी समस्या का समाधान हो गया होगा!


0

मेरे लिए राज्य को उसकी प्रारंभिक स्थिति में रीसेट करने के लिए, मैंने निम्नलिखित कोड लिखा:

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

0

स्वीकार किए गए उत्तर में एक बात यह है कि पैरामीटर चयनकर्ताओं के लिए कैश स्पष्ट नहीं है। यदि आपके पास इस तरह का चयनकर्ता है:

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

फिर आपको उन्हें लॉगआउट पर इस तरह जारी करना होगा:

selectTotal.release();

अन्यथा चयनकर्ता के अंतिम कॉल और अंतिम मापदंडों के मान अभी भी स्मृति में होंगे।

कोड नमूने ngrx डॉक्स से हैं


0

मेरे लिए सबसे अच्छा काम करने के initialStateबजाय इसके बजाय सेट करना है state:

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

-1

एक अन्य विकल्प यह है:

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

'@@redux/INIT'जब आप createStoreअपने आप को पुनः प्राप्त करते हैं तो एक्शन टाइप स्वचालित रूप से डिस्पैच हो जाता है , इसलिए यह मानकर कि आपके रीड्यूसर पहले से ही डिफ़ॉल्ट हैं, यह उन लोगों को पकड़ लेगा और आपके राज्य को नए सिरे से शुरू कर देगा। यह redux का एक निजी कार्यान्वयन विवरण माना जा सकता है, हालांकि, खरीदार सावधान रहें ...


मैंने किया कि यह राज्य नहीं बदल रहा है, मैंने भी @@ INIT की कोशिश की है जो ReduxDevtools में पहली कार्रवाई के रूप में दिखाया गया है
रेजा

-2

बस आपका लॉगआउट लिंक स्पष्ट सत्र है और पृष्ठ को ताज़ा करें। आपके स्टोर के लिए कोई अतिरिक्त कोड की आवश्यकता नहीं है। किसी भी समय आप जिस स्थिति को पूरी तरह से रीसेट करना चाहते हैं उसे पृष्ठ रीफ़्रेश करना एक सरल और आसानी से दोहराने योग्य तरीका है।


1
यदि आप एक मिडलवेयर का उपयोग करते हैं जो स्टोर को लोकलस्टोरेज के लिए सिंक करता है? फिर अपने दृष्टिकोण बिल्कुल काम नहीं करता है ...
स्पॉक

8
मैं वास्तव में यह नहीं समझता कि लोग इस तरह से जवाब क्यों नहीं देते हैं।
व्यालियम जुड

लोगों ने इसे क्यों कम किया है? जब आप एक नया रिडक्स राज्य करते हैं, तो रिक्त सामग्री के साथ, आपके पास मूल रूप से अभी भी स्मृति में पिछले राज्य होते हैं, और आप सैद्धांतिक रूप से उनके साथ डेटा तक पहुंच सकते हैं। ब्राउज़र को ताज़ा करना आपकी सबसे सुरक्षित शर्त है!
विल्हेम सोरबन 17

-3

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


समझाने? @SinanSamet
निकिता बेज्निकोविक

यह स्पष्ट करने के लिए कि मैंने इसे वोट नहीं दिया। लेकिन मैं इसे हतोत्साहित करता हूं। यदि आप लॉगिन करने के लिए नेविगेट करते हैं और पुनः लोड करते हैं तो आप शायद हाँ लॉगआउट करेंगे। लेकिन केवल इसलिए कि आपने अपना राज्य खो दिया। जब तक आप redux-persist का उपयोग नहीं करते हैं उस स्थिति में जब तक आप लॉगआउट नहीं करेंगे। कुल मिलाकर, मुझे बस ऐसे कार्यों को देखने से घृणा है जैसेwindow.location.reload();
सिनान समेट

- इस तरह के कार्यों को न लिखें। - क्यों? - मुझे यह पसंद नहीं है।
निकिता बेज्निकोविक

1
पृष्ठ को पुन: लोड करना स्टोर स्थिति को रीसेट करने से अलग है। इसके अलावा, आप बिना किसी वातावरण में हो सकते हैं window, जैसे कि प्रतिक्रिया-
मैक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.