상태 관리를 위해 Redux를 사용하고 있습니다.
상점을 초기 상태로 재설정하는 방법
예를 들어 두 개의 사용자 계정 ( u1
및 u2
) 이 있다고 가정 해 보겠습니다 .
다음과 같은 일련의 이벤트를 상상해보십시오.
-
사용자
u1
가 앱에 로그인하여 무언가를 수행하므로 저장소에 일부 데이터를 캐시합니다. -
사용자가
u1
로그 아웃했습니다. -
사용자
u2
는 브라우저를 새로 고치지 않고 앱에 로그인합니다.
이 시점에서 캐시 된 데이터가에 연결 u1
되고 정리하고 싶습니다.
첫 번째 사용자가 로그 아웃 할 때 Redux 스토어를 초기 상태로 재설정하려면 어떻게해야합니까?
답변
그렇게하는 한 가지 방법은 응용 프로그램에서 루트 감속기를 작성하는 것입니다.
루트 리듀서는 일반적으로 작업 처리를로 생성 된 리듀서에 위임합니다 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
후 초기 상태로 돌아가 도록 새로운 것을 가르쳐야합니다 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와 동일한 영향을 미치는 한 가지 방법입니다.