[javascript] Redux 스토어의 상태를 재설정하는 방법은 무엇입니까?

상태 관리를 위해 Redux를 사용하고 있습니다.
상점을 초기 상태로 재설정하는 방법

예를 들어 두 개의 사용자 계정 ( u1u2) 이 있다고 가정 해 보겠습니다 .
다음과 같은 일련의 이벤트를 상상해보십시오.

  1. 사용자 u1가 앱에 로그인하여 무언가를 수행하므로 저장소에 일부 데이터를 캐시합니다.

  2. 사용자가 u1로그 아웃했습니다.

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

이 시점에서 캐시 된 데이터가에 연결 u1되고 정리하고 싶습니다.

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



답변

그렇게하는 한 가지 방법은 응용 프로그램에서 루트 감속기를 작성하는 것입니다.

루트 리듀서는 일반적으로 작업 처리를로 생성 된 리듀서에 위임합니다 combineReducers(). 그러나 USER_LOGOUT액션 을받을 때마다 초기 상태를 다시 한 번 반환합니다.

예를 들어 루트 리듀서가 다음과 같은 경우

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

이름을 바꾸고 appReducerrootReducer위임을 작성할 수 있습니다 .

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발사 할 때마다 모든 감속기가 새로 초기화됩니다. 그들은 또한 그들이 확인 할 수 있기 때문에 그들이 원한다면 처음과 다른 것을 반환 할 수 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);
};


답변

Dan Abramov가 승인 한 의견은이 접근 방식과 함께 반응 라우터 리덕스 패키지를 사용할 때 이상한 문제가 발생하는 것을 제외하고는 정확하다고 지적하고 싶습니다. 우리의 수정은 상태를 설정하지 undefined않고 현재 라우팅 감속기를 사용하는 것이 었습니다 . 이 패키지를 사용하는 경우 아래 솔루션을 구현하는 것이 좋습니다.

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


답변

조치를 정의하십시오.

const RESET_ACTION = {
  type: "RESET"
}

그런 다음 각 감속기를 통해 여러 작업을 사용 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를 사용하여이 조치를 가로 챌 수 있습니다. 그러나 두 가지 방법 모두 다른 조치 ‘재설정’을 발송할 수 있습니다. 이 방법으로 상점 로그 아웃 및 재설정은 동 기적으로 발생하며 상점은 다른 사용자 로그인을 준비합니다.


답변

최상의 답변에 대한 간단한 답변 :

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


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


답변

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

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

   return state
 }

초기 저장소로 재설정하려는 모든 또는 일부 감속기에서 처리하는 작업을 실행할 수도 있습니다. 한 번의 작업으로 전체 상태로 재설정하거나 자신에게 적합한 부분 만 재설정 할 수 있습니다. 나는 이것이 가장 간단하고 제어 가능한 방법이라고 생각합니다.


답변

Redux를 사용하면 다음 솔루션을 적용 한 경우 모든 감속기에서 initialState를 설정했다고 가정합니다 (예 : {user : {name, email}}). 많은 구성 요소에서 이러한 중첩 속성을 확인 하므로이 수정 사항을 사용하면 결합 된 속성 조건에서 렌더링 메서드가 손상되는 것을 방지합니다 (예 : 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)
}


답변

NGRX4 업데이트

NGRX 4로 마이그레이션하는 경우 마이그레이션 가이드 에서 감속기를 결합하기위한 rootreducer 방법이 ActionReducerMap 방법으로 대체되었음을 알 수 있습니다. 처음에,이 새로운 일을하는 방식은 상태를 재설정하는 것을 어렵게 만들 수 있습니다. 실제로는 간단하지만이를 수행하는 방법이 변경되었습니다.

이 솔루션은 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와 동일한 영향을 미치는 한 가지 방법입니다.