React/React Library

[Redux] Redux Toolkit: 생산성을 높이는 리덕스 라이브러리

J-Plum 2023. 4. 15. 04:03

리덕스 툴킷!

 

와.. 제가 이거 이해하려고 한참을 공부했내요..

 

제가 이해한게 틀렸다면 언제든지 지적 해주세요! 

 

아래에서 사용할 단어를 간단하게 정리했습니다

 

처음엔 어려워서 이해가 가지 않을 수 있습니다.

 

어렵더라도 끝까지 읽어보시고 마지막에 간단하게 정리된 내용까지 읽어보신다면...

아마도..?

 

store : store 어플리케이션의 전체 상태(state) 저장하고, 이를 변화시키는 action reducer 함수를 포함합니다.

전역으로 상태를 관리함으로써 컴포넌트 간의 데이터 공유가 용이해지고, 중앙 집중적으로 상태를 관리할 있습니다.

(여기서 만든 store을 provider에 사용함으로써 provider의 하위 컴포넌트에서 전역으로 상태를 관리할 수 있게 됩니다.)

 

action : action은 state를 변경할 때 dispatch와 함깨 사용하는 객체입니다. (일반적으로 액션 객체라고 부릅니다)

(액션 생성자 함수를 통해 액션 객체를 반환하며, 액션 생성자 함수는 밑에서 추가로 설명하겠습니다.)

 

reducer : 이전 상태와 액션 객체를 받아서 새로운 상태를 반환하는 함수입니다. reducer는 순수 함수여야하며, 불변성을 지켜야합니다.

(자세한 내용과 사용방법은 아래에 있습니다)

 


리덕스 툴킷의 구조를 만들어보겠습니다

 

1. store만들기

provider에 넣어서 관리를 하기위한 store를 만듭니다 

 1-1. configureStore를 통해 store만들기

 1-2. reducer를 넣어주기 (지금은 리듀서가 없습니다.! 나중에 와서 넣어줄껍니다..)

 


 

2. provider 만들기

Provider로 감싸줍니다. 이전에 만든 store를 넣어 위와 같이 감싸주면,그 안에 있는 컴포넌트들이 store를 이용할 수 있게 됩니다. 


3. slice 만들기

- slice란 Redux store의 상태(state), action, reducer를 하나의 모듈로 묶어서 관리하기 위한 개념입니다.

 여기서 만든 slice는 configureStore 로 만든 store의  상태를 관리하기 위한 모듈입니다.

- createSlice를 사용하여 slice를 생성할 수 있습니다.

(createSlice 사용하면 리덕스 툴킷이 자동으로 리듀서 함수를 생성하는데, 불변성을 지키기 위해 immer를 사용하여 내부적으로 리듀서 함수를 추가합니다.. 위에서 말한 불변성을 지키기 위한 코드를 작성하지 않아도 됩니다.)

name : slice의 이름,

initialState : state의 초기값,

reducers : reducers 에 선언한 함수들은 각각 actions, reducer 프로퍼티에 들어갑니다.

(slice.actions,  slice.reducer 등으로 사용합니다. 위에선 actions를 구조분해할당으로 사용하기 편하게 작성했습니다)

 

actions : actions는 reducers에 있는 함수들을 통해 액션 생성자 함수를 생성해 가지고 있습니다. 

actions 에있는 increment, decrement, incrementByAmount 등(액션 생성자 함수) 를 이용해서 액션 객체를 생성하며, 액션 객체를  dispatch 와 같이 사용해서 state를 변환합니다.

 

reducerreducer에는 slice의 전반적인 내용이 담겨있습니다. (reducers와 다릅니다!)

(name, initialState, reducer등. 각종 자료가 담겨있습니다.)

 

여기서 만든 createSlice 를 통해 만들어진 actions, reducer를 이제 각각 사용해보겠습니다.


4. 다시store로 !

여기서 이제 configureStore 의 reducer: 부분에서 createSlice로 만든 reducer(counterReducer) 를 여기서 사용합니다.

 

(counterReducer 로 넘어온 이유는 counterSlice.reducer 가 counterReducer입니다,

export defalut로 counterReducer를 넘겼습니다. counterSlice를 넘겨  아래와 같이 사용할 수 있으나. 권장하지 않습니다.)


 

configureStore에서 reducer를 직접 만들지않고 createSlice로 만든 reducer를 쓰는 이유는 

slice의 reducer는 내부적으로 immer를 통해 불변성을 유지해주면서 새로운 상태를 반환 해주는 리듀서를 만듭니다.

 

createSlice 사용하지 않고 직접 reducer 함수를 만들어야 한다면, 해당 함수 안에서 상태를 변경하는 코드를 작성할 매번 새로운 객체를 생성하고 기존의 상태와 새로운 값을 합쳐서 반환해주어야 불변성을 유지할 있습니다. 이러한 작업은 번거롭고 실수하기 쉬운 작업이기 때문에, createSlice 사용하면 해당 부분을 자동으로 처리해줌으로써 코드 작성을 쉽고 간단하게 만들어줍니다.

 

정리하면

slice의 reducer 안에는 immer를 사용해 만든 reducer 함수와, slice의 기본적인 정보(이름, 초기 상태값)등이 들어있습니다. 그 정보를 하나의 객체 안에 담아서 사용하는 것 입니다.

reducer : {

      counter : counterReducer

}

위의 코드는  counter라는 state를 정의하고, 그 state를 관리하기 위해 reducer(counterReducer) 라는 함수를 사용한다는 의미입니다.

 

설명이 이상하지만 저런식으로 이해하시면 됩니다.


5. 실제 사용 부분

1. useSelector() 를 이용해서 store에 들어있는 값을 가져옵니다.

2. state.counter.value는 상태값을 의미하며 count에 넣었습니다.

3. useDispatch() 를 통해서 dispatch를 사용합니다. 

4. createSlice를 통해 만든 counterSlice.actions(액션 생성자 함수)를 구조분해 할당해서 가져왔고 dispatch에서 사용합니다.

(dispatch는 액션 객체를 받아서 리듀서 함수를 호출합니다)

5. dispatch에는 액션 객체가 들어가기 떄문에 액션생성자를 사용합니다.

increment, decrement의 경우 액션 생성자를 통해 액션 객체를 생성합니다.

(액션 객체 안에는 typepayload 프로퍼티가 있습니다. 그외에 다른 프로퍼티를 추가로 포함시킬 수 있으나 권장하지않음)

액션 객체의 type을 통해서 type에 맞는 리듀서 함수를 호출합니다.

 

별도의 값이 필요하지않은 리듀서 함수는 첫번째 인자인 state만 받아 사용합니다.

 

 

하지만 incrementByAmount 경우, dispatch(incrementByAmount(5))처럼 인자로 5 넘겨서 호출하면, 5만큼 증가하도록 액션 객체가 생성됩니다. (여기서 5가 payload 에 해당됩니다)

payload가 필요한 incrementByAmount 라는 리듀서 함수는 두번째 인자로 action객체를 받습니다

action객체의 payload를 통해 입력한 값을 상태에 적용합니다.

 

 

 

 


리덕스 툴킷을 공부하며..

 

저는 리덕스 툴킷에 대해 공부하면서 처음 접했을때 이 구조가 쉽게 이해 되지 않았습니다.

거의 3~4시간이 넘게 이해한게 맞는지 찾아보고, 시도해보고, AI를 이용해서 검증도 했습니다.

그래서 제가 이해하기 쉬운대로.. 이해한 그대로 작성해봤습니다.

 

정확하지 않을 수 있습니다.  chatGpt를 통해 많이 물어보고 이해한게 맞다는 답을 들었습니다. 하지만 chatGPT가 틀렸을 수 있습니다.

 

그래도 지금까지 제가 사용하면서 오류가 난 부분은 없습니다.

 

혹시라도 틀렸다면 언제든지 지적해주시면 감사하겠습니다.