const wrapper = createWrapper<Store>(configureStore, {
debug: process.env.NODE_ENV === 'development',
});
export default wrapper.withRedux(MyApp);
import produce from 'immer';
// reducer
const reducer = (state = initialState, action: IAction) => {
return produce(state, (draft) => {
switch (action.type) {
// lecture list initial load
case LOAD_ALL_LECTURES_REQUEST:
draft.loadLectureLoading = true;
break;
}
});
};
export default reducer;
const { createLectureLoading, createLectureData, createLectureDone } = useSelector(
(state: RootState) => state.lecture // selector함수를 useSelector 에 전달
);
const dispatch = useDispatch();
dispatch({
type: SAVE_COURSE_INFO_REQUEST,
data,
});
const store = configureStore({
reducer: Reducer<S, A> | ReducersMapObject<S, A>,
middleware?: ((getDefaultMiddleware: CurriedGetDefaultMiddleware<S>) => M) | M,
devTools?: boolean | DevToolsOptions, // 안쓰였으나 쓸 것 같음
preloadedState?: PreloadedState<CombinedState<NoInfer<S>>>, // 안쓰였음
enhancers?: StoreEnhancer[] | ConfigureEnhancersCallback, // 안쓰였음
})
// _app.tsx
import '../styles/globals.css'
import { Provider } from 'react-redux'
import type { AppProps } from 'next/app'
import store from '../app/store'
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
)
}
export const selectCount = (state: AppState) => state.counter.value;
const count = useAppSelector(selectCount);
<span>{count}</span>
export const counterSlice = createSlice({
name: "counter",
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: {
// 이 안에 있는 함수들이 actionCreator 들이네
increment: (state) => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
// The `extraReducers` field lets the slice handle actions defined elsewhere,
// including actions generated by createAsyncThunk or in other slices.
extraReducers: (builder) => {
builder
.addCase(incrementAsync.pending, (state) => {
state.status = "loading";
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = "idle";
state.value += action.payload;
});
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
console.log("increment() : actionCreator", increment()); // {type: 'counter/increment', payload: undefined}
<button
className={styles.button}
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
비교 | without toolkit | Reudx toolkit |
---|---|---|
store | wrapper(createWrapper)에 store를 전달해서 wrapper로 app을 감싸줌(HOF) Provider로 감싸는 거랑 똑같음 | Provider로 감싸줌(app) |
reducer | switch문에서 action(type)을 확인하고 그것에 맞게 state 변경 | Slice에 reducer들이 포함되어 있고 reducers object에서 key를 골라서 호출하면 reducer에 의해 state가 변경 됨 - 호출방법 : slice.action에 의해 자동으로 매칭되어 생성된 action creator를 dispatch를 통해 호출 |