일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 자동차수리시스템
- NestedFor
- 환경설정
- Java
- 추상메서드
- 생성자오버로드
- 정수형타입
- 자바
- 컬렉션 타입
- 사용자예외클래스생성
- 메소드오버로딩
- 대덕인재개발원
- 어윈 사용법
- exception
- cursor문
- 객체 비교
- 참조형변수
- 예외처리
- EnhancedFor
- 한국건설관리시스템
- 다형성
- 예외미루기
- abstract
- 컬렉션프레임워크
- oracle
- 제네릭
- 오라클
- 인터페이스
- 집합_SET
- GRANT VIEW
- Today
- Total
거니의 velog
(7) 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 2 본문
3. 리덕스 관련 코드 작성하기
* 이제 프로젝트에 리덕스를 사용해 보자. 리덕스 관련 코드를 준비하자. 리덕스를 사용할 때는 액션 타입, 액션 생성 함수, 리듀서 코드를 작성해야 한다. 이 코드들을 각각 다른 파일에 작성하는 방법도 있고, 기능별로 묶어서 파일 하나에 작성하는 방법도 있다.
* 위 그림은 가장 일반적인 구조로 actions, constrains, reducers 라는 세 개의 디렉터리를 만들고 그 안에 기능별로 파일을 하나씩 만드는 방식이다. 코드를 종류에 따라 다른 파일에 작성하여 정리할 수 있어서 편리하지만, 새로운 액션을 만들 때마다 세 종류의 파일을 모두 수정해야 하기 때문에 불편하기도 하다. 이 방식은 리덕스 공식 문서에서도 사용되므로 가장 기본적이라 할 수 있지만, 사람에 따라서는 불편할 수도 있는 구조이다.
* 위 그림은 액션 타입, 액션 생성 함수, 리듀서 함수를 기능 별로 파일 하나에 몰아서 다 작성하는 방식이다. 이러한 방식을 Ducks 패턴이라고 부르며, 앞서 설명한 일반적인 구조로 리덕스를 사용하다가 불편함을 느낀 개발자들이 자주 사용한다.
* 리덕스 관련 코드에 대한 디렉터리 구조는 정해진 방법이 없기 때문에 마음대로 작성해도 되지만, 위 두 가지 방법이 주로 사용된다. 우리는 두 번째로 소개한 방식인 Ducks 패턴을 사용하여 코드를 작성해 보겠다.
(1) counter 모듈 작성하기
* Ducks 패턴을 사용하여 액션 타입, 액션 생성 함수, 리듀서를 작성한 코드를 '모듈'이라고 한다. 먼저 counter 모듈을 작성해 보자.
[1] 액션 타입 정의하기
* modules 디렉터리를 생성하고 그 안에 counter.js 파일을 다음과 같이 작성하자.
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
* 가장 먼저 해야 할 작업은 액션 타입을 정의하는 것이다. 액션 타입은 대문자로 정의하고, 문자열 내용은 '모듈 이름/액션 이름'과 같은 형태로 작성한다. 문자열 안에 모듈 이름을 넣음으로써, 나중에 프로젝트가 커졌을 때 액션의 이름이 충돌되지 않게 해 준다. 예를 들어 SHOW 혹은 INITIALIZE라는 이름을 가진 액션은 쉽게 중복될 수 있다. 하지만 앞에 모듈 이름을 붙여 주면 액션 이름이 겹치는 것을 걱정하지 않아도 된다.
[2] 액션 생성 함수 만들기
* 액션 타입을 정의한 다음에는 액션 생성 함수를 만들어 주어야 한다.
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
* 더 필요하거나 추가할 값이 없으니 그냥 위와 같이 만들어 주면 된다. 꽤 간단하다. 여기서 주의해야 할 점은 앞부분에 export라는 키워드가 들어간다는 것이다. 이렇게 함으로써 추후 이 함수를 다른 파일에서 불러와 사용할 수 있다.
[3] 초기 상태 및 리듀서 함수 만들기
* 이제 counter 모듈의 초기 상태와 리듀서 함수를 만들어 주자.
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
const initialState = {
number: 0,
};
function counter(state = initialState, action) {
switch (action.type) {
case INCREASE:
return {
number: state.number + 1,
};
case DECREASE:
return {
number: state.number - 1,
};
default:
return state;
}
}
export default counter;
* 이 모듈의 초기 상태에는 number 값을 설정해 주었으며, 리듀서 함수에는 현재 상태를 참조하여 새로운 객체를 생성해서 반환하는 코드를 작성해 주었다. 마지막으로 export default로 내보내 주었는데, 두 방식의 차이점은 export는 여러 개를 내보낼 수 있지만 export default는 단 한 개만 내보낼 수 있다는 것이다.
* 불러오는 방식도 다르다. 다음과 같이 말이다.
import counter from './counter';
import { increase, decrease } from './counter';
// 한꺼번에 불러오고 싶을 때
import counter, { increase, decrease } from './counter';
(2) todos 모듈 만들기
* 이번에 만들 모듈은 좀 더 복잡하다. modules 디렉터리에 todos.js 파일을 생성하자.
[1] 액션 타입 정의하기
* 이전과 마찬가지로 가장 먼저 해야 할 일은 액션 타입 정의이다.
const CHANGE_INPUT = 'todos/CHANGE_INPUT'; // 인풋 값을 변경함
const INSERT = 'todos/INSERT'; // 새로운 todo를 등록함
const TOGGLE = 'todos/TOGGLE'; // todo를 체크/체크 해제함
const REMOVE = 'todos/REMOVE'; // todo를 제거함
[2] 액션 생성 함수 만들기
* 다음으로 액션 생성 함수를 만든다. 조금 전과 달리 이번에는 액션 생성 함수에서 파라미터가 필요하다. 전달받은 파라미터는 액션 객체 안에 추가 필드로 들어가게 된다.
const CHANGE_INPUT = 'todos/CHANGE_INPUT'; // 인풋 값을 변경함
const INSERT = 'todos/INSERT'; // 새로운 todo를 등록함
const TOGGLE = 'todos/TOGGLE'; // todo를 체크/체크 해제함
const REMOVE = 'todos/REMOVE'; // todo를 제거함
export const changeInput = (input) => ({
type: CHANGE_INPUT,
input,
});
let id = 3; // insert가 호출될 때마다 1씩 더해진다.
export const insert = (text) => ({
type: INSERT,
todo: {
id: id++,
text,
done: false,
},
});
export const toggle = (id) => ({
type: TOGGLE,
id,
});
export const remove = (id) => ({
type: REMOVE,
id,
});
* 위 액션 생성 함수 중에서 insert 함수는 액션 객체를 만들 때 파라미터 외에 사전에 이미 선언되어 있는 id라는 값에도 의존한다. 이 액션 생성 함수는 호출될 때마다 id 값에 1 씩 더해 준다. 이 id 값은 각 todo 객체가 들고 있게 될 고윳값이다.
* 여기서 id 값이 3인 이유는 다음 절에서 초기 상태를 작성할 때 todo 객체 두 개를 사전에 미리 넣어 둘 것이므로 그 다음에 새로 추가될 항목의 id가 3이기 때문이다.
[3] 초기 상태 및 리듀서 함수 만들기
* 이제 모듈의 초기 상태와 리듀서 함수를 작성한다. 이번에는 업데이트 방식이 조금 까다로워진다. 객체에 한 개 이상의 값이 들어가므로 불변성을 유지해 주어야 하기 때문이다. spread 연산자(...)를 잘 활용하여 작성해 보자. 배열에 변화를 줄 때는 배열 내장 함수를 사용하여 구현하면 된다.
const CHANGE_INPUT = 'todos/CHANGE_INPUT'; // 인풋 값을 변경함
const INSERT = 'todos/INSERT'; // 새로운 todo를 등록함
const TOGGLE = 'todos/TOGGLE'; // todo를 체크/체크 해제함
const REMOVE = 'todos/REMOVE'; // todo를 제거함
export const changeInput = (input) => ({
type: CHANGE_INPUT,
input,
});
let id = 3; // insert가 호출될 때마다 1씩 더해진다.
export const insert = (text) => ({
type: INSERT,
todo: {
id: id++,
text,
done: false,
},
});
export const toggle = (id) => ({
type: TOGGLE,
id,
});
export const remove = (id) => ({
type: REMOVE,
id,
});
const initialState = {
input: '',
todos: [
{
id: 1,
text: '리덕스 기초 배우기',
done: true,
},
{
id: 2,
text: '리액트와 리덕스 사용하기',
done: false,
},
],
};
function todos(state = initialState, action) {
switch (action.type) {
case CHANGE_INPUT:
return {
...state,
input: action.input,
};
case INSERT:
return {
...state,
todos: state.todos.concat(action.todo),
};
case TOGGLE:
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo,
),
};
case REMOVE:
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.id),
};
default:
return state;
}
}
export default todos;
(3) 루트 리듀서 만들기
* 이번 프로젝트에서는 리듀서를 여러 개 만들었다. 나중에 createStore 함수를 사용하여 스토어를 만들 때는 리듀서를 하나만 사용해야 한다. 그렇기 때문에 기존에 만들었던 리듀서를 하나로 합쳐 주어야 하는데, 이 작업은 리덕스에서 제공하는 combineReducers 라는 유틸 함수를 사용하면 쉽게 처리할 수 있다.
* modules 디렉터리에 index.js 파일을 만들고, 그 안에 다음과 같은 코드를 작성하자.
import { combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';
const rootReducer = combineReducers({
counter,
todos,
});
export default rootReducer;
* 파일 이름을 이렇게 index.js로 설정해 주면 나중에 불러올 때 디렉터리 이름까지만 입력하여 불러올 수 있다. 다음과 같이 말이다.
import rootReducer from './modules';
4. 리액트 애플리케이션에 리덕스 적용하기
* 이제 드디어 리액트 애플리케이션에 리덕스를 적용할 차례이다. 스토어를 만들고 리액트 애플리케이션에 리덕스를 적용하는 작업은 src 디렉터리의 index.js에서 이루어진다.
(1) 스토어 만들기
* 가장 먼저 스토어를 생성한다.
[src/index.js]
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createStore } from 'redux';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './modules';
const store = createStore(rootReducer);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
reportWebVitals();
(2) Provider 컴포넌트를 사용하여 프로젝트에 리덕스 적용하기
* 리액트 컴포넌트에서 스토어를 사용할 수 있도록 App 컴포넌트를 react-redux에서 제공하는 Provider 컴포넌트로 감싸 준다. 이 컴포넌트를 사용할 때는 store를 props로 전달해 주어야 한다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './modules';
const store = createStore(rootReducer);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>,
);
reportWebVitals();
(3) Redux DevTolls의 설치 및 적용
* Redux RevTools는 리덕스 개발자 도구이며, 크롬 확장 프로그램으로 설치하여 사용할 수 있다. 크롬 웹 스토어에서 Redux DevTools를 검색하여 설치해 주자.
https://chromewebstore.google.com/search/Redux%20Devtools?hl=ko
* 설치하고 나면 리덕스 스토어를 만드는 과정에서 다음과 같이 적용해 줄 수 있다.
// 사용 예시
const store = createStore(
rootReducer, /* preloadedState, */
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
* 하지만 패키지를 설치하여 적용하면 코드가 훨씬 깔끔해진다. 우리는 패키지를 설치하는 형태로 적용해 보겠다(패키지를 설치하여 사용한다고 해도 크롬 확장 프로그램은 설치해야 한다).
* 우선 redux-devtools-extension을 yarn을 사용하여 설치해 주자.
$ yarn add redux-devtools-extension
* 그리고 다음과 같이 적용해 주면 된다.
[src/index.js]
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './modules';
const store = createStore(rootReducer, composeWithDevTools());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>,
);
reportWebVitals();
* 이제 브라우저에서 크롬 개발자 도구를 실행한 후 Redux 탭을 열어 보자. 리덕스 개발자 도구가 잘 나타나는가?
* 리덕스 개발자 도구 안의 State 버튼을 눌러 현재 리덕스 스토어 내부의 상태가 잘 보이는지 확인해 보자.
'React > React_리액트 심화' 카테고리의 다른 글
(9) 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 4 (0) | 2023.12.13 |
---|---|
(8) 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 3 (0) | 2023.12.13 |
(6) 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 1 (0) | 2023.12.13 |
(5) 리덕스 라이브러리 이해하기 2 (0) | 2023.12.13 |
(4) 리덕스 라이브러리 이해하기 1 (0) | 2023.12.13 |