0.라이브러리를 사용한 상태관리를 해야하는 이유?
리액트 네이티브 프로젝트에서 여러 화면 간에 공유해야하는 상태가 있거나 한 화면이라도 컴포넌트 렌더 트리에서 서로 멀리 떨어져 있는 컴포넌트간에 상태를 공유할 때는 전역 상태를 관리해줘야한다. 이건 나중에 좀 더 자세히 포스팅하기로 한다...
초기상태 설정 -> 액션 생성 및 디스패치 -> 리듀서 호출(수행) -> 상태 업데이트 -> UI 업데이트
조금 더 구체적으로 동작원리를 설명해보도록 하겠다.
1. 동작원리 설명
예시를 들어서 동작원리에 대해 설명해보겠다!
사용자의 동작 | 동작 | 동작원리 단계 |
사용자가 increment 버튼 클릭 | = 버튼 클릭등의 액션 발생 | 1. View 에서 액션을 수행 |
dispatch({type:"INCREMENT"}) | = dispatch 함수를 사용해 액션을 스토어로 보냄 = dispatch(increment())가 호출되어 "INCREMENT" 액션이 스토어로 전달 |
2. dispatch 함수로 store 로 액션을 전달 |
리듀서가 카운터 값을 1 증가시킴 | =스토어는 액션을 리듀서에 전달 =리듀서는 현재 상태와 액션을 받아 새로운 상태를 계산하여 반환 |
3. action 에 해당되는 리듀서 수행 |
새로운 값이 스토어에 저장된다. | =리듀서가 반환한 새로운 상태가 스토어에 저장 =스토어는 상태 변경을 구독자에게 알림 |
4. state 업데이트 |
카운터 값을 표시하는 컴포넌트가 새로운 값을 출력 | =상태변경을 구독한 컴포넌트가 새로운 상태에 따라 다시 렌더링됨 | 5. 업데이트된 state를 view에서 받아서 출력 |
2. 기본용어
액션(Action)
- 상태를 변경하기 위해 발생시키는 신호 또는 메시지
- 액션은 상태가 어떻게 변해야 하는지를 설명하는 객체로, Redux에서 상태 변경을 요청하는 유일한 방법
- 상태(state) 의 변화를 일으키기 위한 정보를 담고있는 객체이다.
- 액션은 스토어에 보내져서 상태를 변경하는데 사용된다.
- type: 액션의 유형을 나타냄 (리듀서가 어떤 종류의 상태 변경을 해야하는지를 구별)
- payload: 선택적 속성/ 액션이 전달하는 데이터 (사용자가 입력한 값이나 서버에서 받은 데이터를 포함가능)
// 액션 객체 예시
{
type: 'auth/setEmail',
payload: 'user@example.com'
}
-> 이렇게 하면 auth/setEmail 이라는 종류의 상태를 user@example.com 라는 이메일주소 데이터를 포함하고 있다.
리듀서(Reducer)
- 액션을 처리하여 상태를 업데이트 하는 함수이다.
- 현재 상태와 액션 객체를 인자로 받아 새로운 상태를 반환.
- 순수함수여야 하며 상태를 직접 변경하지않고 새로운 상태 객체를 반환해야한다.
- 예를 들어, 카운터를 증가시키는 리듀서는 현재 카운터 값을 1증가시킨 새로운 값을 반환한다.
스토어(Store)
- Redux 애플리케이션의 상태를 보관하고 관리하는 중앙 저장소이다.
- 애플리케이션의 모든 상태(state)를 하나의 객체로 관리하며, 상태를 읽고 수정하는 다양한 메서드를 제공한다.
디스패치(Dispatch)
- 상태를 변경하기 위해 정의된 액션 (action) 을 스토어에 보내는 함수이다.
- 디스패치를 통해 액션이 리듀서로 전달되고, 상태가 변경된다.
- 디스패치는 명령을 전달하는 행위이다.
- 즉 액션이 디스패치 되었다 = 액션이 스토어로 보내졌다는 의미이다.
- 액션이 스토어로 디스패치되면, 스토어는 해당 액션을 받아 리듀서(reducer) 함수를 호출하여 현재 상태를 업데이트
프로바이더(Provider)
- react 애플리케이션에서 redux 스토어를 사용할 수 있도록 해준다.
- 애플리케이션의 최상위에 위치하여 모든 자식 컴포넌트가 스토어에 접근할 수 있도록 해준다.
미들웨어(Middleware)
- 액션이 디스패치 된 후 리듀서가 이를 처리하기 전에 실행되는 추가 로직이다.
- 예를들어 로그를 남기거나 비동기 요청을 처리하는데 사용된다.
슬라이스(Slice)
- redux toolkit 에서 상태의 한 부분과 그 상태를 변경하는 로직을 한 곳에 모아서 관리하는 단위 개념이다
- 슬라이스를 사용하면 액션과 리듀서를 한번에 정의할 수 있다.
- Redux에서는 액션, 액션 생성자, 리듀서 등을 각각 별도로 정의해야 하지만,
- Redux Toolkit의 createSlice 함수는 이 모든 것을 한 번에 정의할 수 있도록 도와준다.
- name: 슬라이스의 이름을 정의, 액션타입을 지정할 때 도움
- initialState:초기값을 정의
- reducers: 상태를 변경하는 함수들. 각 함수는 state와 action을 인자로 받아 상태를 업데이트하는 로직을 포함.
구독 (Subscription)
- 특정 데이터나 이벤트의 변화를 감지하고 해당 변경 사항을 애플리케이션의 특정부분에 반영하는 역할을 한다.
- 상태가 변경될 때마다 특정 콜백함수를 호출하도록 설정하여
- 컴포넌트나 다른 코드가 상태 변경을 감지하고 작업을 수행하도록 한다.
3. 사용법 개념 정리
프로젝트에 Provider 를 사용하여 리덕스를 적용하면 useSelector Hook 을 사용하여 리덕스의 상태를 조회할 수 있고
useDispatch 를 사용해 액션을 발생시켜 상태를 업데이트 할 수 있다.
- 리덕스를 사용할 때는 상태의 종류별로 모듈을 작성한다.
- 모듈에는 액션타입, 액션 생성 함수, 리듀서를 선언한다.
- 여러 리듀서를 combineReducers로 합쳐 루트 리듀서를 만든다.
- createStore를 사용하여 스토어를 만든다.
- Provider를 사용하여 리액트 프로젝트에 리덕스를 적용한다.
- useSelector 와 useDispatch 를 사용하여 리덕스의 상태를 조회하거나 업데이트 한다.
4. Redux Toolkit 이란?
- 리덕스의 모듈을 작성하는 일은 매우 귀찮다. -> 업데이트를 하나 할 때마다 준비해야할 코드가 많다...
- ex) 액션 타입을 선언하고... 액션 생성함수를 선언하고...리듀서에서 해당 액션을 위한 케이스를 작성해야하고..ㅠ
- 따라서 모듈의 상태가 복잡해지면 불변성을 유지하면서 상태를 업데이트 하기 위해 작성해야 할 코드의 양도 많아질 수 밖에 없다.
==> 이런 불편한 점들을 개선하기 위하여 Redux toolkit 을 개발하였다.
그렇다면 장점이 뭔데??
- 액션타입, 액선생성함수, 리듀서를 한번에 작성할 수 있다.
- 상태를 업데이트할 때 불변성에 대해 신경쓰지 않아도 된다.
- 상태를 직접 업데이트 했을 때 내장된 라이브러리 immer 사용하여 불변성을 유지하면서 업데이트 해준다.
- 리듀서와 액션 생성 함수가 동시에 만들어지기 때문에 액션 타입을 따로 선언할 필요가 없다.
5. Redux toolkit 만의 기본 개념엔 뭐가 있을깜...
- configureStore: 스토어 설정을 단순화하고, 미들웨어와 개발자 도구 확장을 자동으로 설정
- createSlice: 액션과 리듀서를 한 곳에서 정의한다. slice 를 만들면 counterSlice.actions 는 액션 생성함수들이 들어있는 객체를, counterSlice. reducer를 리듀서 함수를 가리킨다. 만약...액션 타입을 조회해야할 일이 생기면 액션 생성 함수의 type 필드를 확인하면 된다.
- createAsyncThunk: 비동기 로직을 간단하게 처리할 수 있도록 도와준다.
- createEntityAdapter: 정규화된 상태를 더 쉽게 관리할 수 있게 한다.
- slice 를 만들 때 name 을 지정해줘야한다. -> 작성한 name 은 액션 타입이 만들어질 때 name/ 액션이름 형태로 사용이 된다. 예를들어 .. 현재 slice 이름이 counter라면 increase의 액션 타입은 counter/ increase가 된다.
6. redux toolkit 사용하기
1. 설치하기
npm install @reduxjs/toolkit
npm install react-redux
2. 슬라이스 생성하기
상태와 리듀서를 정의하는 슬라이스 생성하기
import { createSlice } from '@reduxjs/toolkit';
const initialState = { value: 0 };
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
}
}
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
* 추후 다른 곳에서 사용할 것이기 때문에 export 해준다.
3. 스토어 설정
슬라이스에서 생성한 리듀서를 사용하여 스토어를 설정
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
4. Provider 설정
React 애플리케이션에서 Redux 스토어를 사용할 수 있도록 Provider 컴포넌트를 설정
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './app/store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
5. React 컴포넌트에서 상태와 액션 사용
React 컴포넌트에서 useSelector와 useDispatch 훅을 사용하여 상태를 조회하고 액션을 디스패치한다.
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
<button onClick={() => dispatch(incrementByAmount(2))}>Increment by 2</button>
</div>
);
}
export default Counter;
6. 앱 컴포넌트에 Counter 컴포넌트 포함
최종적으로, Counter 컴포넌트를 앱에 포함시켜 렌더링
import React from 'react';
import Counter from './features/counter/Counter';
function App() {
return (
<div className="App">
<Counter />
</div>
);
}
export default App;
7. 타입스크립트와 함께 사용하기
Redux Toolkit 은 타입스크립트를 공식적으로 지원하기 때문에 타입스크립트 환경에서도 쉽게 사용할 수 있다.
두가지를 주의해야한다.
- initialState 에 타입 달아주기
- 액션 타입에 PayloadAction 사용하기
'React' 카테고리의 다른 글
[React] 상태관리 라이브러리란? (0) | 2024.08.04 |
---|---|
[React] API 활용한 영화 웹페이지 만들기 (2) (0) | 2024.07.12 |
[React] 조건부연산자(=삼항연산자) (1) | 2024.07.08 |
[React] API 활용한 영화 웹페이지 만들기 (1) (0) | 2024.07.04 |
[React] 전역상태관리 (0) | 2024.06.25 |