React | 상태관리 : Redux
8326 단어 Reactredux-toolkitreduxReact
Redux의 핵심 원칙
- Single source of truth : store는 단 하나이며, 모든 앱의 상태는 이곳에 보관된다.
- Immutability : 상태는 오로지 읽을 수만 있으며 변경하려면 '모든 상태'가 변경되어야 한다. 재생성시에는 새로운 객체 혹은 새로운 어레이가 생성되어야 한다.
- Pure function : 상태의 변경은 어떠한 사이드 이펙트도 만들지 않아야 한다.
👉 Reducer에서는 상태를 변경하면 안되며, '새로운 상태'를 리턴해야 한다.
👉 변경을 만들기 위해서는 dispatch를 이용해야 한다.
1. Action
- 상태의 변경을 나타내는 개념
- 어떤 형태든지 상관 없지만 주로 type, payload를 포함하는 js 객체
const action1 = {
type: "namespace/getMyData",
payload : {
id: 123
}
};
👉 잘개 쪼개서 작은 상태의 변경을 나타내어 여러 action을 합쳐 복합 형태를 나타내기에 유용함.
2. Action Creator
- Action을 생성하는 함수
- 직접 action을 생성하는 것보다 action creator를 활용하면 재사용성이 좋고, 하나의 레이어를 추가할 수 있다.
👉 id를 받아서 action object를 만들어줌
👉 또 다른 형태의 layer를 두게 됨(id : String(id).slice(1) 부분)
👉 addObj(id)를 넘기면 액션이 생성됨
const addObj = (id) => {
type: 'namespace/getMyData',
payload: {
id: String(id).slice(1)
}
}
3. Store
- 앱 전체의 상태를 보관하는 곳
- action에 따라 reducer에는 새로운 상태를 만들어 내며, store에는 그 상태를 저장한다.
- 상태 불변, 매 액션이 발생할 때마다 새로운 객체가 만들어짐
const store = createStore(reducer, initialState);
4. Reducer
- action을 받아서 새로운 state를 만든다.
👉 console.log, axios.get() 등이 들어가지 않아야 한다.
const Reducer = (state, action) => {
switch (action.type) {
case "namespcae/getMyData":
const obj = {id: action.payload.id}
return {
...state, obj
};
default:
return state;
}
};
5. Dispatch
- action을 redux로 보내는 함수
- dispatch 후에 action은 middleware를 거쳐서 reducer에 도달한다.
👉 dispatch(action object) -> middleware -> reducer - dispatch() 안에는 action object를 생성해서 해당 action을 넘겨야 한다.
function MyApp() {
const dispatch = useDispatch()
return (
<button onClick={
() => dispatch(addObj(1234))
}>Submit</button>
)
}
6. Selector
- 특정 state 조각을 store로부터 가져오는 함수
- store의 state는 raw data를 저장하고, 계산된 값을 selector로 가져올 수 있다.
function MyApp() {
const dispatch = useDispatch()
const obj = useSelector(state => state.obj)
return (
<button onClick={
() => dispatch(addObj(1234))
}>Submit</button>
)
}
⚡ flux : action -> dispatch -> reducer -> store -> selector
👉 action이 들어오면 dispatch는 reducer로 이를 전달하며, reducer는 action type에 따라 새로운 state를 리턴한다. 그러면 이는 store에 저장되며 여기에 저장된 state를 사용하기 위해 selector를 사용한다.
Redux의 구조
- Middleware : action object가 reducer에 진입하기 전에 동작한다.
- Enhancer : 전체 state의 상태를 중심으로 redux의 동작을 확장한다.
👉 예시로는 Middleware가 있다.
👉 Middleware는 action object가 promise를 리턴하는지 체크한다.
Redux-toolkit 활용
- redux에서 공식저으로 추천하는 helper 라이브러리이다.
👉 redux-devtools, immerjs, redux-thunk, reselect 등의 라이브러리가 미리 포함되어 있다.
1. configureStore
- redux의 createStore 함수를 래핑한다.
👉 createStore를 사용할 때보다 간단하게 작성할 수 있다.
const store = configureStore({
reducer : {
posts: postsReducer,
users: usersReducer
}
})
2. createAction
- Action creator를 만드는 함수
- 만들어진 action creator에 데이터를 넘기면 payload 필드로 들어간다.
const addPost = createAction('post/addPost')
addPost({title: 'post 1'})
3. createReducer
- reducer를 만듦
- builder의 addCase 메서드를 이용해서 action마다 state의 변경을 정의한다.
- immerjs를 내부적으로 사용하게 때문에 mutable code를 이용해서 간편하게 변경된 코드를 작성할 수 있다.
const postsReducer = createReducer(initState,
builder => {
builder.addCase(addPost, (state, action) => {
state.posts.push(action.payload)
})
}
)
4. createSlice
- Slice는 action creator, reducer 등 별도로 만들어야 하는 여러 redux 구현체를 하나의 객체로 모은 것이다.
const postsSlice = createSlice({
name:'posts',
initialState,
reducers: {
addPost(state, action) {
state.postsSlice.push(action.payload)
}
}
})
// 사용
const { addPost } = postsSlice.actions
const reducer = postsSlice.reducer
5. createSelector
- state를 이용한 특정 데이터를 리턴하도록 한다.
- 리덕스에서 알아서 캐시 관리를 해주어 성능 향상에 도움이 된다.
const postsSelector = state => state.posts
const userSelector = state => state.user
const postsByUserIdSelector = createSelector(
postsSelector,
userSelector,
(posts, user) => {
posts.filter(post => post.username == user.username)
}
)
Redux를 React에 연결하기
1. Provider
- Redux store와 React를 연결하기 위해서는 반드시 Provider로 컴포넌트를 감싸야 한다.
- provider 안에서 렌더링된 컴포넌트들은 state에 접근할 수 없다.
function App() {
return (
<Provider store={store}>
<div>소개글입니다.</div>
</Provider>
);
}
2. useDispatch
- redux의 dispatch를 가져오기 위한 API
- dispatch 함수에 action object를 넘겨서 상태 변경을 만든다.
const dispatch = useDispatch();
<Button onClick={() =>
dispatch(changeTheme(theme === "light" ? "dark" : "light"))
}>
3. useSelector
- Redux store로부터 데이터를 얻기 위한 API
- selector fuction을 인자로 넘긴다.
function Header() {
const dispatch = useDispatch();
const theme = useSelector((state) => state.theme);
<Button onClick={() =>
dispatch(changeTheme(theme === "light" ? "dark" : "light"))
}>
Redux를 이용한 비동기 처리
- 비동기를 위한 middleware를 추가해야 한다.
- redux-thunk는 Promise를 이용한 비동기 action을 쉽게 처리하도록 하는 middleware
👉 이외에도 redux-saga, redux-observable 등이 있다.
1. createAsyncThunk
- redux-toolkit에서는 thunk middleware를 디폴트로 추가한다.
- redux-toolkit은 createAsyncThunk API를 제공한다.
사용방법
- 두 인자 "action type", "async callback(payload creator)"을 받는다.
- creataeAsyncThunk로 만들어진 action creator는 4가지 함수로 구성된다.
👉 addPost : async 함수를 dispatch 하는 함수
👉 addPost.pending : promise를 생성했을 때 발생하는 액션
👉 addPost.fulfilled : fulfilled 되었을 때 발생하는 액션
👉 addPost.rejected : rejected 되었을 때 발생하는 액션
const addPost = createAsyncThunk('posts/addPost',
async (title) => {
const result = await PostAPI.addPost({ title })
return result.data
}
)
useEffect(() => {
dispatch(addPost("post 1"))
}, [])
- createSlice의 extraReducers 함수를 이용해서 builder에 각 상황에 대한 리듀서를 추가할 수 있다.
👉 즉, pending, fulfilled, rejected 각 상황에 대한 리듀서를 추가할 수가 있다.
2. 연속적인 비동기 처리
- thunk 함수를 dispatch하면 promise를 리턴하는데, 이 때 .then() 메소드로 연속적인 비동기 처리를 이어 실행할 수 있다.
Author And Source
이 문제에 관하여(React | 상태관리 : Redux), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@combi_jihoon/React-상태관리-Redux3저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)