programing

Redux 스토어 상태를 리셋하는 방법

prostudy 2022. 10. 13. 23:23
반응형

Redux 스토어 상태를 리셋하는 방법

리덕스
스토어를 초기 상태로 리셋하려면 어떻게 해야 하나요?

가 두의 사용자 계정(예: 2개의 사용자 계정)을 있다고해 보겠습니다.u1 ★★★★★★★★★★★★★★★★★」u2를 참조해 주세요.
이치노

  1. " "u1앱에 로그인해서 뭔가를 하기 때문에 스토어에 데이터를 캐시합니다.

  2. " "u1로그아웃 합니다.

  3. " "u2브라우저를 새로 고치지 않고 앱에 로그인합니다.

는 " "와 .u1청소하고 싶습니다.

첫 번째 사용자가 로그아웃할 때 Redux 저장소를 초기 상태로 재설정하려면 어떻게 해야 합니까?

이를 위한 한 가지 방법은 응용 프로그램에 루트 리덕터를 쓰는 것입니다.

, 를, 에된 리덕터에 합니다.combineReducers() 수신할 마다, 수신할 수 있습니다USER_LOGOUT초기 .action은 원래 상태로 되돌립니다.

예를 들어 루트 리덕터가 다음과 같은 경우:

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

, 이제 것을 주면 .rootReducerUSER_LOGOUT액션.아시다시피, 리듀서는 다음과 같이 호출되면 초기 상태를 반환해야 합니다.undefined첫 번째 논쟁으로 삼을 수 있습니다. 이 된 것을 해 볼까요?state을 리리에 .appReducer:

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

  return appReducer(state, action)
}

이제 제, now, 언, 지, nowUSER_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는 스토리지 엔진에 상태 복사본을 보관하며, 상태 복사본은 새로 고침 시 그곳에서 로드됩니다.

먼저 적절한 스토리지 엔진을 Import한 후 다음 상태로 설정하기 전에 상태를 해석해야 합니다.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);
};

Dan Abramov의 답변은 정확합니다.단, 이 접근방식과 함께 react-router-redux 패키지를 사용할 때 이상한 문제가 발생했습니다.

를 「(으)」로 하지 않는 이었습니다.undefined현재의 라우팅 리듀서를 사용합니다. 이 아래의 합니다.

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

액션을 정의합니다.

const RESET_ACTION = {
  type: "RESET"
}

으로 각 에서는 리듀서(Reduceer)를 사용하고 합니다.에서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 stateaction, reducer로 스토어를 합니다.

로그아웃의 경우 다음과 같은 처리를 할 수 있습니다.

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

사용자가 로그인할 때마다 브라우저를 새로 고치지 않습니다.스토어는 항상 기본값이 됩니다.

store.dispatch(RESET_ACTION)목적을 위한 입니다.그 목적을 위한 액션 크리에이터가 있을 가능성이 높습니다. 더 좋은 은 씬씬 a a a a a a a a a a a a a a a a a a a a a a a a a a a a가 있는 입니다.LOGOUT_ACTION

this 를 디스패치하면LOGOUT_ACTION커스텀 미들웨어는 Redx-Saga 또는 Redx-Thunk를 사용하여 이 액션을 대행 수신할 수 있습니다.다만, 어느 쪽이든, 다른 액션 「RESET」를 디스패치 할 수 있습니다.이렇게 하면 스토어 로그아웃 및 리셋이 동기화되어 스토어가 다른 사용자 로그인을 준비할 수 있습니다.

Dan Abramov의 답변대한 간단한 답변입니다.

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


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

Redux Toolkit 및/또는 Typescript 사용:

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

const rootReducer = (
  state: ReturnType<typeof appReducer>,
  action: AnyAction
) => {
/* if you are using RTK, you can import your action and use it's type property instead of the literal definition of the action  */
  if (action.type === logout.type) {
    return appReducer(undefined, { type: undefined });
  }

  return appReducer(state, action);
};
 const reducer = (state = initialState, { type, payload }) => {

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

   return state
 }

또한 초기 저장소로 재설정하려는 모든 또는 일부 환원 장치가 처리하는 작업을 실행할 수도 있습니다.한 번의 작업으로 전체 상태로 리셋하거나 사용자에게 적합한 일부 상태로 리셋할 수 있습니다.나는 이것이 이것을 하는 가장 간단하고 통제하기 쉬운 방법이라고 믿는다.

에서 사용자를 로그아웃할 때 인 상태 "cookie")를입니다.localStorage,IndexedDB,Web SQL 리프레시)를 사용하여 를 새로 고칩니다window.location.reload()로 또는 수 window 에서는, DOM 하는 것만이, 한 방법입니다모든 영속적인 상태를 삭제하고 브라우저를 새로 고치는 것이 이전 사용자의 정보가 다음 사용자에게 유출되지 않도록 하는 유일한 방법입니다.

(물론 공유 컴퓨터 사용자라면 '프라이빗 브라우징' 모드를 사용하거나 브라우저 창을 직접 닫거나 '브라우징 데이터 클리어' 기능 등을 사용해야 하지만 개발자로서 모두가 항상 부지런할 것이라고는 기대할 수 없습니다.)

Redx를 사용하여 Redx를 합니다.initialState(예: 모든 리듀서)에 포함되어 있습니다.{ user: { name, email }} 네스트에 이된 속성 "예: "가" "예: "가" "예: "가" "이 경우")에서 되는 것을 state.user.emailuser 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)
}

NGRX4 업데이트

NGRX 4로 이행하는 경우 이행가이드에서 다음 사항을 알 수 있습니다.rootreducer이 듀를 the the the the 로 되었습니다.ActionReducerMap를 재설정하는것이 .처음에, 이 새로운 방식의 일은 국가를 다시 세우는 것을 어렵게 만들 수 있다.이것은 사실 간단하지만, 이것을 하는 방법은 바뀌었습니다.

이 솔루션은 NGRX4 Github 문서의 meta-reducers API 섹션에서 영감을 받았습니다.

NGRX의 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에서도 같은 효과를 얻을 수 있는 하나의 방법입니다.

Dan Abramov의 답변에 따라 작성된 타이프스크립트를 사용할 때의 회피책(리듀스 타이핑은 합격할 수 없음)undefined첫 번째 인수로 reducer하기 때문에 초기 루트 상태를 상수로 캐시합니다).

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

로그아웃 링크를 클리어하고 페이지를 갱신하기만 하면 됩니다.스토어에 추가 코드는 필요 없습니다.상태를 완전히 재설정하려면 페이지 새로 고침을 단순하고 쉽게 반복할 수 있습니다.

redux-actions를 사용하는 경우 HOF(Higher Order Function)를 사용한 간단한 회피책을 소개합니다.handleActions.

import { handleActions } from 'redux-actions';

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

다음에 and고 and and를 사용합니다.handleActionsExhandleActions리듀서를 다룰 수 있습니다.

댄의 답변은 이 문제에 대한 좋은 아이디어를 주지만 잘 풀리지 않았다.왜냐하면 나는 이 문제를 사용하고 있기 때문이다.redux-persist.
「 」와 함께 redux-persist지나치다undefined지속 동작을 트리거하지 때문에 것을 알았습니다(내 경우 Native, 즉 내 NativeAsyncStorage를 참조해 주세요.

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

또는

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

저도 안 먹혔어요.그냥 소리만 질렀어요.(예: "뜻밖의 열쇠 _ persist..."라고 불평하는 등)

건 '다 하다'가 '다'가 '다'가 '다'가 '다'가 '다'가'가 되면 환원제가 '' 예요. 내가 원하는 건 단지 모든 개별 리듀서를 초기 상태로 되돌리는 것뿐이에요.RESET이치노그렇게 하면 끈기가 자연스럽게 처리됩니다.위用함수)가 없는 것은 분명합니다.handleActionsEx 「 않습니다( 1개의 라이너에 ).RESET: () => initialState메타프로그래밍을 너무 좋아해서 견딜 수가 없었어요.

Dan Abramov의 답변, Ryan Irilli답변, 그리고 Rob Moorman의 답변조합하여, 이 답변이 유지되는 이유를 설명합니다.router스테이트 트리의 다른 모든 것을 초기화하면 다음과 같은 결과가 됩니다.

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

나는 상태를 정리하기 위한 행동을 만들었다.따라서 로그아웃액션 작성자를 디스패치할 때는 클리어 스테이트에도 액션을 디스패치합니다.

사용자 레코드 액션

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

이게 최선인지 잘 모르겠어요.

Redx가 초기 상태의 동일한 변수를 참조하지 않도록 하기 위한 나의 조치:

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

수를 만들었습니다를 강화하고 Redux를 .이 컴포넌트를 사용하여 스토어를 강화하고 특정 컴포넌트를 디스패치하면 됩니다.action.type트리거합니다.구현에 대한 생각은 Dan Abramov가 답변에서 말한 과 동일합니다.

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

다음과 같은 해결책이 나에게 효과가 있었다.

메타 리듀서에 리셋 상태 기능을 추가했습니다.열쇠는 사용법이었다.

return reducer(undefined, action);

이치노 ★★★★undefined오히려 가게의 구조가 파괴되어 오류가 발생하고 있었습니다.

/syslogers/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.disc.ts

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

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

아브라모프의 답변이 사건을 해결하는 데 도움이 되었다.그러나, 나는 전체 상태를 클리어 할 필요가 없는 경우를 만났다.그래서 이렇게 했어요.

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;

@dan-abramov answer의 확장일 뿐입니다.특정 키가 리셋되지 않도록 유지해야 할 경우가 있습니다.

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

이 접근방식은 매우 옳습니다.특정 상태 "NAME"을 파기하여 다른 상태를 무시하고 유지합니다.

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

상태를 초기 상태로 리셋하기 위해 다음 코드를 작성했습니다.

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

아브라모프답변이 내게는 잘 먹혔지만, 그것이 ESLint를 촉발시켰다.no-param-reassign오류 - https://eslint.org/docs/rules/no-param-reassign

대신 다음과 같이 대처하고, 반드시 상태 복사본을 작성합니다(내 이해로는, Redoxy 작업입니다).

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

하지만 주정부의 복사본을 만드는 것이 좀 복잡할 수도 있습니다.이것은 그다지 좋은 것은 아니지만, 보다 요령 있게 읽혀지고 있습니다.

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

먼저 응용 프로그램 시작 시 리듀서 상태는 새로워지고 기본 InitialState로 새로워집니다.

APP 초기 로드에 대해 호출하는 액션을 추가하여 기본 상태유지해야 합니다.

응용 프로그램에서 로그아웃하는 동안 기본 상태재할당하면 리듀서도 새 것과 동일하게 작동합니다.

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

로그아웃 시 상태 리셋을 위한 호출 액션

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

Dan Abramov의 답변으로는 파라미터화된 셀렉터의 캐시를 클리어할 수 없습니다.다음과 같은 셀렉터가 있는 경우:

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 문서에서 가져온 것입니다.

나에게 효과가 있는 빠르고 쉬운 옵션은 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'
})

Redux Toolkit을 사용한 접근법:


export const createRootReducer = (history: History) => {
  const rootReducerFn = combineReducers({
    auth: authReducer,
    users: usersReducer,
    ...allOtherReducers,
    router: connectRouter(history),
  });

  return (state: Parameters<typeof rootReducerFn>[0], action: Parameters<typeof rootReducerFn>[1]) =>
    rootReducerFn(action.type === appActions.reset.type ? undefined : state, action);
};

왜 그냥 사용하지 않는거죠?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 statementswitch 내부로 합니다.

또 다른 옵션은 다음과 같습니다.

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

'@@redux/INIT'는 redux가 redux를 사용할 때 입니다.createStore모든 리듀서가 이미 디폴트값이 되어 있다고 가정하면 리듀서가 디폴트값이 디폴트값이 되어 상태가 새롭게 시작됩니다.단, redex의 프라이빗 구현 세부사항으로 간주될 수 있으므로 구매자는 주의하시기 바랍니다.

저에게 가장 효과가 있었던 것은,initialStatestate:

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

단일 리듀서를 리셋하는 경우

예를들면

const initialState = {
  isLogged: false
}
//this will be your action
export const resetReducer = () => {
  return {
    type: "RESET"
  }
}

export default (state = initialState, {
  type,
  payload
}) => {
  switch (type) {
    //your actions will come her
    case "RESET":
      return {
        ...initialState
      }
  }
}

//and from your frontend
dispatch(resetReducer())

언급URL : https://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store

반응형