Bagaimana cara mereset keadaan toko Redux?

455

Saya menggunakan Redux untuk manajemen negara.
Bagaimana cara mereset toko ke keadaan awal?

Sebagai contoh, katakanlah saya memiliki dua akun pengguna ( u1dan u2).
Bayangkan urutan kejadian berikut:

  1. Pengguna u1masuk ke aplikasi dan melakukan sesuatu, jadi kami menyimpan beberapa data di toko.

  2. Pengguna u1keluar.

  3. Pengguna u2masuk ke aplikasi tanpa menyegarkan peramban.

Pada titik ini, data yang di-cache akan dikaitkan dengan u1, dan saya ingin membersihkannya.

Bagaimana saya bisa mereset toko Redux ke keadaan awal ketika pengguna pertama log out?

xyz
sumber
8
Mungkin lebih baik untuk menghapus negara pada logout sebagai gantinya (dari perspektif keamanan)
Clarkie

Jawaban:

1033

Salah satu cara untuk melakukannya adalah dengan menulis peredam root di aplikasi Anda.

Root reducer biasanya akan mendelegasikan penanganan aksi ke reducer yang dihasilkan oleh combineReducers(). Namun, setiap kali ia menerima USER_LOGOUTtindakan, ia mengembalikan keadaan awal dari awal lagi.

Misalnya, jika peredam root Anda terlihat seperti ini:

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

Anda dapat mengubah nama appReducerdan menulis rootReducerdelegasi baru untuk itu:

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

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

Sekarang kita hanya perlu mengajarkan yang baru rootReduceruntuk mengembalikan keadaan awal setelah USER_LOGOUTtindakan. Seperti yang kita ketahui, reduksi seharusnya mengembalikan keadaan awal ketika mereka dipanggil dengan undefinedargumen pertama, apa pun tindakannya. Mari kita gunakan fakta ini untuk menghapus secara akumulatif akumulasi yang statekita berikan appReducer:

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

  return appReducer(state, action)
}

Sekarang, setiap kali USER_LOGOUTkebakaran, semua reduksi akan diinisialisasi lagi. Mereka juga dapat mengembalikan sesuatu yang berbeda dari yang mereka lakukan pada awalnya jika mereka mau karena mereka dapat memeriksa action.typejuga.

Untuk mengulangi, kode lengkap baru terlihat seperti ini:

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

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

  return appReducer(state, action)
}

Perhatikan bahwa saya tidak mengubah keadaan di sini, saya hanya menetapkan ulang referensi variabel lokal yang dipanggil statesebelum meneruskannya ke fungsi lain. Mutasi objek negara akan melanggar prinsip Redux.

Jika Anda menggunakan redux-persist , Anda mungkin juga perlu membersihkan penyimpanan Anda. Redux-persist menyimpan salinan status Anda di mesin penyimpanan, dan salinan status akan dimuat dari sana saat refresh.

Pertama, Anda perlu mengimpor mesin penyimpanan yang sesuai dan kemudian, untuk menguraikan status sebelum mengaturnya undefineddan membersihkan setiap kunci status penyimpanan.

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);
};
Dan Abramov
sumber
15
Saya ingin tahu Dan, bisakah Anda juga melakukan sesuatu seperti ini di peredam Anda. dengan CLEAR_DATA sebagai aksinya. case 'CLEAR_DATA': return initialState
HussienK
6
@ HussienK yang akan bekerja tetapi tidak pada negara untuk setiap peredam.
Cory Danielson
12
Berikut adalah versi di mana Anda secara dinamis menggabungkan reduksi jika Anda menggunakan reduksi async: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
Apakah pendekatan ini sepenuhnya membersihkan negara dan semua sejarahnya? Saya berpikir dari sudut pandang keamanan: Jika ini telah diterapkan, begitu USER_LOGOUTaksi telah dipecat, apakah mungkin untuk mendapatkan data negara dari sebelumnya? (mis. via devtools)
AlexKempton
81

Saya ingin menunjukkan bahwa komentar yang diterima oleh Dan Abramov benar kecuali kami mengalami masalah aneh ketika menggunakan paket react-router-redux bersama dengan pendekatan ini. Perbaikan kami adalah untuk tidak mengatur keadaan, undefinedtetapi masih menggunakan peredam perutean saat ini. Jadi saya akan menyarankan menerapkan solusi di bawah ini jika Anda menggunakan paket ini

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    const { routing } = state
    state = { routing } 
  }
  return appReducer(state, action)
}
Ryan Irilli
sumber
19
Saya pikir kesimpulannya di sini adalah bahwa Anda mungkin tidak ingin menghapus seluruh pohon status pada logout - pendekatannya bekerja dengan baik pada peredam akar dari setiap subtree, dan jadi mungkin lebih jelas untuk menerapkan teknik ini hanya pada peredam akar dari subtree (s) Anda tidak ingin menghapus, daripada memilih keluar 'khusus' anak-anak untuk tidak jelas di peredam akar seluruh pohon, seperti ini
davnicwil
1
Saya pikir saya mengalami masalah yang Anda maksudkan saat ini, (di mana saat logout akan mengatur jalur ke jalur yang benar tetapi komponen yang berbeda akan dimuat) saya menerapkan sesuatu yang mirip dengan Anda untuk memperbaikinya, tetapi saya pikir sesuatu dengan js abadi sedang mengumpulkan ini. Saya akhirnya membuat reducer induk yang memiliki tindakan RESET-STATE, dan saya mewarisi dari reducer itu untuk menghindari menyentuh routing sama sekali
Neta Meta
Mengalami masalah serupa, ini telah memperbaikinya. Terima kasih.
Lloyd Watkin
3
Perhatikan bahwa dengan react-redux-router, properti itu routerdan TIDAKrounting
Mrchief
2
@Mrchief itu tergantung apa yang Anda definisikan sebagai combineReducers()..... Anda jika Anda memilikinya combineReducers({routing: routingReducer})akan seperti yang dijelaskan dalam jawaban
Ben Lonsdale
40

Tentukan tindakan:

const RESET_ACTION = {
  type: "RESET"
}

Kemudian di setiap reduksi Anda dengan asumsi Anda menggunakan switchatau if-elseuntuk menangani beberapa tindakan melalui masing-masing reducer. Saya akan mengambil kasing untuk 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; 
  }
}

Dengan cara ini setiap kali Anda memanggil RESETtindakan, peredam Anda akan memperbarui toko dengan status default.

Sekarang, untuk keluar Anda dapat menangani hal-hal di bawah ini:

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

Setiap kali pengguna masuk, tanpa peramban peramban. Store akan selalu default.

store.dispatch(RESET_ACTION)hanya menguraikan ide. Anda kemungkinan besar akan memiliki pembuat tindakan untuk tujuan tersebut. Cara yang jauh lebih baik adalah Anda memiliki LOGOUT_ACTION.

Setelah Anda mengirim ini LOGOUT_ACTION. Kemudian middleware kustom dapat mencegat tindakan ini, baik dengan Redux-Saga atau Redux-Thunk. Namun demikian, Anda dapat mengirim tindakan lain 'RESET'. Dengan cara ini penyimpanan dan pengaturan ulang toko akan terjadi secara serempak dan toko Anda akan siap untuk login pengguna lain.

nirbhaygp
sumber
1
Saya merasa ini adalah pendekatan yang lebih baik daripada hanya mengatur keadaan undefinedseperti pada jawaban lainnya. ketika aplikasi Anda mengharapkan pohon negara dan Anda memberikannya undefined, hanya ada lebih banyak bug dan sakit kepala yang harus dihadapi daripada sekadar pohon kosong.
worc
3
@worc Negara tidak akan benar-benar tidak terdefinisi, karena reduksi mengembalikan initialState ketika mereka menerima keadaan tidak terdefinisi
Guillaume
3
@ worc berpikir bahwa dengan pendekatan ini, setiap kali ada orang yang membuat peredam baru Anda harus ingat untuk menambahkan case reset.
Francute
1
Saya benar-benar mengubah pikiran saya tentang ini, karena kedua alasan itu, ditambah gagasan bahwa RESET_ACTION adalah tindakan . jadi itu tidak benar-benar termasuk dalam peredam untuk memulai.
worc
1
Ini jelas merupakan pendekatan yang tepat. Menyetel keadaan menjadi apa pun kecuali Initial State hanya meminta masalah
Sebastian Serrano
15

Hanya jawaban yang disederhanakan untuk jawaban terbaik:

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


export default (state, action) =>
  rootReducer(action.type === 'USER_LOGOUT' ? undefined : state, action);
Matt Carlotta
sumber
ini bekerja terima kasih, saya dari jawaban Dan tetapi saya tidak bisa mengetahuinya.
Aljohn Yamaro
14
 const reducer = (state = initialState, { type, payload }) => {

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

   return state
 }

Anda juga dapat menjalankan tindakan yang ditangani oleh semua atau beberapa reduksi, yang ingin Anda atur ulang ke penyimpanan awal. Satu tindakan dapat memicu reset ke seluruh negara Anda, atau hanya sebagian yang tampaknya cocok untuk Anda. Saya percaya ini adalah cara paling sederhana dan paling terkendali untuk melakukan ini.

Daniel petrov
sumber
10

Dengan Redux jika telah menerapkan solusi berikut, yang mengasumsikan saya telah menetapkan status awal di semua reduksi saya (misalnya {user: {name, email}}). Dalam banyak komponen saya memeriksa properti bersarang ini, jadi dengan perbaikan ini saya mencegah metode rendering saya rusak pada kondisi properti digabungkan (misalnya jika state.user.email, yang akan melempar pengguna kesalahan tidak ditentukan jika solusi yang disebutkan di atas).

const appReducer = combineReducers({
  tabs,
  user
})

const initialState = appReducer({}, {})

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

  return appReducer(state, action)
}
Rob Moorman
sumber
7

MEMPERBARUI NGRX4

Jika Anda bermigrasi ke NGRX 4, Anda mungkin telah memperhatikan dari panduan migrasi bahwa metode rootreducer untuk menggabungkan reduksi Anda telah diganti dengan metode ActionReducerMap. Pada awalnya, cara baru dalam melakukan sesuatu ini mungkin membuat mengatur ulang keadaan menjadi tantangan. Ini sebenarnya lurus ke depan, namun cara melakukan ini telah berubah.

Solusi ini terinspirasi oleh bagian API meta-reducers dari NGRX4 Github docs.

Pertama, katakanlah Anda menggabungkan pengecil Anda seperti ini menggunakan opsi ActionReducerMap baru NGRX:

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

Sekarang, katakanlah Anda ingin mengatur ulang status dari dalam 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 { }

`

Dan itu pada dasarnya adalah salah satu cara untuk mencapai pengaruh yang sama dengan NGRX 4.

Tyler Brown
sumber
5

Menggabungkan pendekatan dari Dan, Ryan dan Rob, untuk memperhitungkan menjaga routernegara dan menginisialisasi segala sesuatu yang lain di pohon negara, saya berakhir dengan ini:

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

Saya telah membuat komponen untuk memberikan Redux kemampuan mengatur ulang keadaan, Anda hanya perlu menggunakan komponen ini untuk meningkatkan toko Anda dan mengirimkan tindakan tertentu. Ketik untuk memicu reset. Pikiran implementasi sama dengan apa yang dikatakan @Dan Abramov.

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

wwayne
sumber
4

Saya telah membuat tindakan untuk menghapus status. Jadi, ketika saya mengirim pembuat tindakan logout, saya mengirim tindakan untuk menghapus status juga.

Tindakan merekam pengguna

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

Pembuat tindakan logout

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

Peredam

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

Saya tidak yakin apakah ini optimal?

Navinesh Chand
sumber
2

Jika Anda menggunakan aksi redux , inilah solusi cepat menggunakan HOF ( Fungsi Urutan Tinggi ) untuk handleActions.

import { handleActions } from 'redux-actions';

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

Dan kemudian gunakan handleActionsExalih-alih yang asli handleActionsuntuk menangani reduksi.

Jawaban Dan memberi ide bagus tentang masalah ini, tetapi tidak berhasil dengan baik bagi saya, karena saya menggunakan redux-persist.
Ketika digunakan dengan redux-persist, hanya melewati undefinedstatus tidak memicu perilaku bertahan, jadi saya tahu saya harus menghapus item secara manual dari penyimpanan (Bereaksi Asli dalam kasus saya, dengan demikian AsyncStorage).

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

atau

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

juga tidak bekerja untuk saya - mereka hanya berteriak kepada saya. (mis. mengeluh seperti "Kunci tak terduga _persis ..." )

Lalu tiba-tiba saya merenungkan yang saya inginkan hanyalah membuat setiap peredam individu mengembalikan keadaan awal mereka sendiri ketika RESETjenis tindakan ditemui. Dengan begitu, gigih ditangani secara alami. Jelas tanpa fungsi utilitas di atas ( handleActionsEx), kode saya tidak akan terlihat KERING (walaupun itu hanya satu liner, yaitu RESET: () => initialState), tetapi saya tidak tahan karena cuz saya suka metaprogramming.

elquimista
sumber
2

Solusi berikut ini berhasil untuk saya.

Saya menambahkan pengaturan ulang fungsi negara ke meta reducers. Kuncinya adalah menggunakan

return reducer(undefined, action);

untuk mengatur semua reduksi ke kondisi awal. Kembali undefinedmalah menyebabkan kesalahan karena fakta bahwa struktur toko telah hancur.

/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 {}
Pan Piotr
sumber
2

Dari perspektif keamanan, hal paling aman untuk dilakukan ketika login user adalah dengan mengatur ulang semua negara terus-menerus (ex cookies, localStorage, IndexedDB, Web SQL, dll) dan melakukan refresh keras halaman menggunakan window.location.reload(). Mungkin pengembang yang ceroboh secara tidak sengaja atau sengaja menyimpan beberapa data sensitif pada window, di DOM, dll. Menghilangkan semua status persisten dan menyegarkan peramban adalah satu-satunya cara untuk memastikan tidak ada informasi dari pengguna sebelumnya yang bocor ke pengguna berikutnya.

(Tentu saja, sebagai pengguna di komputer bersama Anda harus menggunakan mode "penjelajahan pribadi", tutup sendiri jendela peramban, gunakan fungsi "hapus data penjelajahan", dll, tetapi sebagai pengembang, kami tidak dapat mengharapkan setiap orang untuk selalu seperti itu. rajin itu)

tlrobinson
sumber
1
Mengapa orang membatalkan ini? Ketika Anda melakukan kondisi redux baru, dengan konten kosong, Anda pada dasarnya masih memiliki status sebelumnya dalam memori, dan Anda secara teoritis dapat mengakses data dari mereka. Menyegarkan browser ADALAH taruhan teraman Anda!
Wilhelm Sorban
2

Solusi saya ketika bekerja dengan naskah, dibangun di atas jawaban Dan (pengetikan redux membuatnya tidak mungkin untuk dilewatkan undefinedke reducer sebagai argumen pertama, jadi saya cache kondisi root awal dalam konstanta):

// 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"})
  }
}
Jacka
sumber
2

Jawaban yang diterima membantu saya menyelesaikan kasus saya. Namun, saya menemukan kasus di mana tidak-seluruh-negara harus dibersihkan. Jadi - saya melakukannya dengan cara ini:

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;

Semoga ini bisa membantu orang lain :)

pesho hristov
sumber
bagaimana jika saya memiliki lebih dari 10 status tetapi saya ingin mengatur ulang status hanya satu peredam?
Paul
1

Hanya ekstensi untuk jawaban @ dan-abramov , kadang-kadang kita mungkin perlu mempertahankan kunci tertentu agar tidak disetel ulang.

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);
};
gsaandy
sumber
1

Opsi cepat dan mudah yang bekerja untuk saya menggunakan redux-reset . Yang mudah dan juga memiliki beberapa opsi lanjutan, untuk aplikasi yang lebih besar.

Setup di buat toko

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)

Kirim 'reset' Anda dalam fungsi logout Anda

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

Semoga ini membantu

Munei Nengwenani
sumber
1

Saya ambil untuk menjaga Redux dari referensi ke variabel yang sama dari keadaan awal:

// 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;
  }
};
Hani
sumber
Gagasan untuk menulis status default sebagai fungsi benar-benar menyelamatkan hari di sini. Terima kasih 🙏
Chris Paul
0

Pendekatan ini sangat tepat: Hancurkan negara "NAME" spesifik untuk mengabaikan dan menjaga orang lain.

const rootReducer = (state, action) => {
    if (action.type === 'USER_LOGOUT') {
        state.NAME = undefined
    }
    return appReducer(state, action)
}
khalil zaidoun
sumber
Jika Anda hanya perlu mengatur ulang satu bagian dari pohon negara Anda, Anda juga bisa mendengarkannya USER_LOGOUTdi peredam itu dan menanganinya di sana.
Andy_D
0

kenapa tidak Anda gunakan saja 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;
}

Catatan: pastikan Anda menetapkan nilai default tindakan {}dan Anda OK karena Anda tidak ingin menemukan kesalahan ketika Anda memeriksa action.typedi dalam pernyataan switch.

Fareed Alnamrouti
sumber
0

Saya menemukan bahwa jawaban yang diterima bekerja dengan baik untuk saya, tetapi memicu no-param-reassignkesalahan ESLint - https://eslint.org/docs/rules/no-param-reassign

Inilah cara saya menanganinya, memastikan untuk membuat salinan negara (yang, dalam pemahaman saya, hal yang harus dilakukan 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)
}

Tapi mungkin membuat salinan negara untuk hanya meneruskannya ke fungsi peredam lain yang membuat salinan yang sedikit terlalu rumit? Ini tidak dibaca dengan baik, tetapi lebih penting:

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

Selain jawaban Dan Abramov, seharusnya kita tidak menetapkan tindakan secara eksplisit sebagai action = {type: '@@ INIT'} di samping state = undefined. Dengan jenis tindakan di atas, setiap peredam mengembalikan keadaan awal.

rupav jain
sumber
0

di server, saya punya variabel: global.isSsr = true dan di setiap reducer, saya punya const adalah: initialState Untuk mengatur ulang data di Store, saya melakukan yang berikut dengan setiap Reducer: contoh dengan 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;
        }
    }
}

akhirnya di router server:

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

Solusi berikut ini berfungsi untuk saya.

Pertama pada saat inisiasi aplikasi kita keadaan peredam baru dan baru dengan InitialState default .

Kami harus menambahkan tindakan yang menyerukan inital load APP untuk mempertahankan status default .

Saat keluar dari aplikasi, kita dapat dengan mudah menetapkan ulang status default dan peredam akan berfungsi sama seperti baru .

Wadah Aplikasi Utama

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

Reducer APP Utama

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

On Logout calling action untuk mengatur ulang status

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

Semoga ini bisa menyelesaikan masalah Anda!

Mukundhan
sumber
0

Bagi saya untuk mengatur ulang negara ke keadaan awal, saya menulis kode berikut:

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

Satu hal yang tidak dilakukan solusi dalam jawaban yang diterima adalah menghapus cache untuk penyeleksi parameter. Jika Anda memiliki pemilih seperti ini:

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

Maka Anda harus melepaskannya saat logout seperti ini:

selectTotal.release();

Kalau tidak, nilai memoized untuk panggilan terakhir pemilih dan nilai-nilai parameter terakhir akan tetap dalam memori.

Sampel kode berasal dari ngrx docs .

Grochni
sumber
0

bagi saya yang paling berhasil adalah mengatur initialStatealih - alih state:

  const reducer = createReducer(initialState,
  on(proofActions.cleanAdditionalInsuredState, (state, action) => ({
    ...initialState
  })),
noy levi
sumber
-1

Pilihan lain adalah:

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

'@@redux/INIT'adalah jenis tindakan yang dikirim redux secara otomatis saat Anda createStore, jadi dengan anggapan reduksi Anda sudah memiliki default, ini akan tertangkap oleh mereka dan memulai keadaan Anda dengan segar. Ini mungkin dianggap detail implementasi pribadi redux, jadi pembeli berhati-hatilah ...

lobati
sumber
Saya melakukan itu tidak mengubah keadaan, saya juga mencoba @@ INIT yang ditampilkan di ReduxDevtools sebagai tindakan pertama
Reza
-2

Cukup minta tautan keluar Anda menghapus sesi dan segarkan laman. Tidak diperlukan kode tambahan untuk toko Anda. Kapan pun Anda ingin mengatur ulang sepenuhnya keadaan, segarkan halaman adalah cara sederhana dan mudah diulang untuk menanganinya.

pengguna3500325
sumber
1
Bagaimana jika Anda menggunakan middleware yang menyinkronkan toko ke penyimpanan lokal? Maka pendekatan Anda tidak bekerja sama sekali ...
Spock
8
Saya tidak benar-benar mengerti mengapa orang menurunkan jawaban seperti ini.
Wylliam Judd
Mengapa orang membatalkan ini? Ketika Anda melakukan kondisi redux baru, dengan konten kosong, Anda pada dasarnya masih memiliki status sebelumnya dalam memori, dan Anda secara teoritis dapat mengakses data dari mereka. Menyegarkan browser ADALAH taruhan teraman Anda!
Wilhelm Sorban
-3

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

Nikita Beznosikov
sumber
menjelaskan? @SinanSamet
Nikita Beznosikov
Untuk lebih jelasnya saya tidak memilih ini. Tapi saya tidak menganjurkannya. Jika Anda menavigasi untuk masuk dan memuat ulang, Anda mungkin akan keluar ya. Tetapi hanya karena Anda kehilangan negara Anda. Kecuali Anda menggunakan redux-persisten dalam hal ini Anda bahkan tidak akan keluar. Secara keseluruhan, saya hanya benci melihat fungsi sepertiwindow.location.reload();
Sinan Samet
- Jangan menulis fungsi seperti ini. - Kenapa? - Saya tidak suka itu.
Nikita Beznosikov
1
Memuat ulang halaman berbeda dengan mengatur ulang keadaan toko. Selain itu, Anda mungkin berada di lingkungan tanpa window, mis. Asli-reaksi
Max