[리액트] CRA로 리액트 프로젝트 생성 부터 Redux까지

2023. 4. 26. 15:20개발/React

  • CRA를 통한 리액트 프로젝트 생성
  • Redux설치
  • Duck패턴을 적용한 Redux 사용하기

설치

프로젝트를 생성하고자 하는 경로에서 해당 명령어를 통해 리액트 프로젝트를 생성한다.

yarn create react-app [프로젝트명]

 

생성된 프로젝트 디렉토리로 이동한다.

cd [프로젝트명]

 

yarn add 명령어를 통해서 해당 프로젝트에 리덕스와 react-redux 라이브러리를 설치한다.

yarn add redux
yarn add react-redux

 

프로젝트 구조

리액트에서 Duck패턴으로 리덕스를 적용할때 보다 알아보기 쉽게 하기 위해 프로젝트 폴더를 정리해 보았다.

.
...
├── src
│   ├── components
│   │   └── Counter.jsx
│   ├── redux
│   │   ├── config
│   │   │   └── configStore.js
│   │   ├── modules
│   │   │   └── conter.js
...
│   ├── index.js
...

 

폴더

  •  src/components
    • 컴포넌트를 모아두었다. 스토어에 접근하는 컴포넌트를 컴포넌트컨테이너란 이름으로 별도로 분리하기도 하지만 프로젝트가 작아서 분리 하지는 않았다.
  • src/redux
    • 리덕스 관련 코드를 모두 담은 디렉토리
  • src/redux/config
    • 리덕스 설정 파일을 모은 디렉토리
  • src/redux/modules
    • Duck패턴에 의해 기능별로 하나의 파일에 모아서 작성한 모듈 파일을 담는 디렉토리

 

파일

  •  Counter.jsx
    • 카운터 컴포넌트. 화면에 리턴하는 리액트 엘리먼트를 표현한다.
    • 스토어에 접근해서 값을 가져온다.
  • configStore.js
    • 리듀서들을 모아서 한데 등록하는 루트 리듀서와, 스토어를 만든다.
  • counter.js
    • 액션타입, 액션생성함수, 리듀서를 모두 하나에 작성한 모듈. counter에 관련된 액션, 액션생성함함수, 리듀서를 같는다.
  • index.js
    • react-redux에서 제공하는 Provider 컴포넌트로 감싸서 스토어을 사용할수 있도록 코드를 작성한다.
    • 이때 Provider 컴포넌트에는 store를 Props로 전달해 주어야 한다.

 

코드 작성하기

src/redux/modules/counter.js

/* 0.액션타입 정의 */
const INCREASE = 'counter/INCREASE' 
const DECREASE = 'counter/DECREASE'

/* 1.액션생성함수 */
export const increase = (payload) => {
    return {
        type : INCREASE,
        payload
    }
}

export const decrease = (payload) => {
    return {
        type : DECREASE,
        payload
    }
}

/* 2.초기상태 설정 */
const initState = {
    number : 0
}

/* 3.리듀서 함수 */
function counter(state = initState, action) {
    switch(action.type){
        case INCREASE :
            return {
                number : state.number+1
            }
        case DECREASE :
            return {
                number : state.number-1
            }
        default :
            return state
    }
}

export default counter

 

액션, 초기상태, 리듀서를 포함하고 있는 파일을 생성한다.

  • 액션타입 정의
    • 휴먼에러를 줄이기 위해 액션타입을 선언해준다.
  • 액션생성 함수
    • 정의된 액션타입을 타입으로 가지고 일정한 값을 포함하고 있는 액션객체를 리턴하는 함수들을 선언한다.
    • 선언된 함수는 export 한다. 후에 컴포넌트에서 export된 액션생성 함수를 import해서 사용한다.
  • 초기상태 설정
    • 리듀서에서 사용할 초기상태를 설정해준다.
  • 리듀서함수
    • 초기값과 액션객체를 인자로 받는 리듀서 함수를 선언한다.
    • 리듀서 내부에는 초기값과 액션값으로 어떤 로직을 수행할지 알맞은 로직을 작성한다.

 

src/redux/config/configStore.js

import { createStore } from "redux";
// 루트리듀서에 사용하기 위해 콤빈리듀서 불러옴
import { combineReducers } from "redux";
import counter from "../modules/counter";

/* 4.루트리듀서 만들기 */
const rootReducer =  combineReducers({
    counter : counter,
})

/* 5.스토어 만들기 */
const store =  createStore(rootReducer)

export default store

 

여러 기능별 리듀서들을 모아서 제공하는 루트 리듀서와 스토어를 만든다.

  • 루트리듀서만들기
    • 루트 리듀서를 선언하기 위해서 리덕스 라이브러리에서 제공하는 combineReducers를 import 한다.
    • 리듀서 함수가 포함된 모듈 파일을 import 한다.
    • 리듀서 모듈들이 명시된 객체를 comineReducer에 인자로 담아 루트 리듀서를 선언한다.
  • 스토어 만들기
    • 스토어를 선언하기 위해서 리덕스에서 제공하는 createStore를 Import 한다.
    • 스토어를 선언하고 크리에이트스토어 함수를 사용해서 앞서 선언한 리듀서의 목록객체를 넘겨준다.

 

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

/* 6.리덕스 사용가능 상태로 만들기. */
import { Provider } from 'react-redux';
import store from './redux/config/configStore';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);

 

리덕스를 사용하는 상태를 설정하자.

  • 리덕스 사용가능 상태로 만들기
    • react-redux 라이브러리에서 제공하는 Provider와 앞서 선언한 store 가 담긴 configStore를 import 한다.
    • root.render 아래에 리덕스 영향에 포함될 컴포넌트를 Provider 컴포넌트로 감싼다. 이때 import 해온 store를 props로 내려준다.

 

src/components/Couter.jsx

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
/* 9.dispathcer를 통해 가져올 액션생성함수를 모듈에서 가져온다. */
import { increase, decrease } from '../redux/modules/counter';

function Counter() {
    /* 7.useSelecter 를 통해 스토어의 값을 가져온다*/
    const count = useSelector(state=>state.counter)
    
    /* 8.useDisfatch를 사용해서 스토어의 값을 사용할수 있게 준비한다. */
    const dispatcher = useDispatch()

    /* 10.dispathcer를 통해 리덕스 모듈에 있는 액션생서함수에 접근한다. */
    const onClickEventHandler = (e) => {
        if(e.target.id === 'increase'){
            console.log("증가버튼")
            dispatcher(increase())
        }else{
            console.log("감소버튼")
            dispatcher(decrease())
        }
    }

    return (
        <div>
            <div>{count.number}</div>

            <button id="increase" onClick={onClickEventHandler}>증가</button>
            <button id="decrease" onClick={onClickEventHandler}>감소</button>
        </div>
    )
}

export default Counter;

 

컴포넌트에서 리덕스로 state값 읽고쓰고

  • useSelecter를 통해 스토어의 값을 가져온다.
  • useDispatch를 사용해서 스토어의 값을 사용할 수 있도록 준비한다.
  • 액션생성함수를 모듈에서 가져온다.
  • 준비된 디스패처와 임포프된 액션생성함수를 사용해서 리덕스 액션객체를 넘긴다.
    • 디스패처에서 액션생성 함수를 호출하게 되면 호출된 액션 생성함수에 따라 액션객체가 생성되고 그 액션객체의 타입에 따라 리듀서에서 로직을 수행한다.