579

状態管理に Redux を使用しています。
ストアを初期状態にリセットするにはどうすればよいですか?

たとえば、2 つのユーザー アカウント (u1u2) があるとします。
次の一連のイベントを想像してください。

  1. ユーザーu1がアプリにログインして何かを行うと、一部のデータがストアにキャッシュされます。

  2. ユーザーu1がログアウトします。

  3. ユーザーu2は、ブラウザーを更新せずにアプリにログインします。

この時点で、キャッシュされたデータは に関連付けu1られます。これをクリーンアップしたいと思います。

最初のユーザーがログアウトしたときに Redux ストアを初期状態にリセットするにはどうすればよいですか?

4

36 に答える 36

1255

これを行う 1 つの方法は、アプリケーションにルート レデューサーを記述することです。

ルート レデューサーは通常、アクションの処理を によって生成されたレデューサーに委任しcombineReducers()ます。ただし、アクションを受けるたびにUSER_LOGOUT、最初の状態に戻ります。

たとえば、ルート レデューサーが次のようになっているとします。

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に応答して初期状態に戻るように new を教える必要があります。ご存じのように、レデューサーは、アクションに関係なく、最初の引数としてUSER_LOGOUT呼び出されたときに初期状態を返すことになっています。この事実を使用して、 に渡すときにundefined蓄積されたものを条件付きで取り除きましょう。stateappReducer

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

  return appReducer(state, action)
}

これで、 が起動するたびUSER_LOGOUTに、すべてのレデューサーが新たに初期化されます。また、チェックできるため、必要に応じて最初とは異なるものを返すこともできaction.typeます。

繰り返しますが、完全な新しいコードは次のようになります。

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

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

  return appReducer(state, action)
}

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

        return appReducer(undefined, action);
    }
    return appReducer(state, action);
};
于 2016-02-26T01:54:44.990 に答える
93

Dan Abramov答えは正しいですが、このアプローチで react-router-redux パッケージを使用したときに奇妙な問題が発生しました。

私たちの修正は、状態をに設定するのundefinedではなく、現在のルーティング リデューサーを引き続き使用することでした。したがって、このパッケージを使用している場合は、以下のソリューションを実装することをお勧めします

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    const { routing } = state
    state = { routing } 
  }
  return appReducer(state, action)
}
于 2016-05-20T05:27:01.580 に答える
12

Redux を使用して、次のソリューションを適用した場合initialState、すべてのレデューサーに を設定したと仮定します (例: { user: { name, email }})。多くのコンポーネントで、これらのネストされたプロパティをチェックするため、この修正により、レンダー メソッドが結合されたプロパティ条件 (たとえば、上記のソリューションの場合にstate.user.emailエラーをスローするif ) で壊れないようにします。user is undefined

const appReducer = combineReducers({
  tabs,
  user
})

const initialState = appReducer({}, {})

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

  return appReducer(state, action)
}
于 2016-07-05T09:07:33.970 に答える
4

ログアウト リンクのセッションをクリアして、ページを更新するだけです。ストアに追加のコードは必要ありません。状態を完全にリセットしたいときはいつでも、ページの更新は、それを処理するためのシンプルで簡単に繰り返し可能な方法です。

于 2016-02-26T15:40:45.177 に答える
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
  }
};

これが最適かどうかわかりませんか?

于 2016-09-19T20:02:06.580 に答える
4

Redux に状態をリセットする機能を提供するコンポーネントを作成しました。このコンポーネントを使用してストアを強化し、action.typeリセットをトリガーする特定のものをディスパッチするだけです。実装の考え方は、 Dan Abramovが答えで言ったことと同じです。

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

于 2016-03-26T17:03:16.857 に答える
2

Dan Abramov回答は、私のケースを解決するのに役立ちました。ただし、状態全体をクリアする必要がない場合に遭遇しました。だから私はこのようにしました:

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;
于 2018-11-22T18:36:46.733 に答える
0

このアプローチは非常に正しいです。特定の状態「NAME」を破棄して、他の状態を無視して保持します。

const rootReducer = (state, action) => {
    if (action.type === 'USER_LOGOUT') {
        state.NAME = undefined
    }
    return appReducer(state, action)
}
于 2016-05-31T08:25:02.893 に答える
0

最初にアプリケーションを開始すると、リデューサーの状態は新しく、デフォルトのInitialStateで新しくなります。

デフォルトの状態を維持するために、APP の初期ロードを呼び出すアクションを追加する必要があります。

アプリケーションからログアウトしている間、デフォルトの状態を簡単に再割り当てでき、リデューサーはnewと同じように機能します。

メイン APP コンテナ

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

メインAPPリデューサー

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

状態をリセットするための Logout 呼び出しアクション

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
    });
  }
}
于 2018-08-18T14:25:03.433 に答える
-1

私にとって最もうまくいったのは、のinitialState代わりにを設定することですstate

  const reducer = createReducer(initialState,
  on(proofActions.cleanAdditionalInsuredState, (state, action) => ({
    ...initialState
  })),
于 2020-03-19T11:27:25.593 に答える
-1

なぜあなたはただ使わないのですか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;
}

注: switch ステートメント内{}をチェックするときにエラーが発生したくないため、アクションの既定値を に設定して問題ないことを確認してください。action.type

于 2016-12-02T17:08:30.570 に答える