create-react-app
create-react-app은 사용자가 쉽게 개발을 할 수 있도록 개발 환경을 제공해주는 도구이다. CRA에는 브라우저 호환성을 위한 바벨과 웹팩과 등의 다양한 패키지가 포함되어 있으며, 테스트 시스템, ES6+ 문법, CSS 후처리 등 거의 필수라고 할 수 있는 개발 환경도 구축해 준다.
npx create-react-app '프로젝트 이름'
위의 명령어로 우리는 바로 실행 가능한 react앱을 생성할 수 있다.
이제 create-react-app으로 리액트 프로젝트를 생성하고, redux와 redux-saga 셋팅까지 완료해보자.
React 프로젝트 생성
먼저, CRA로 새로운 프로젝트를 만들어준다.
다음과 같은 메세지가 나오면 성공적으로 프로젝트가 만들어졌다는 뜻이다.
필요없는 파일들은 지워줘야한다.
// package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
package.json
파일 scripts
부분에서 test
, eject
를 지워주었다.
src
폴더에 파일을 App.js
, index.js
만 남기고 모두 제거해준다.
위 절차를 마치면 디렉터리 구조는 다음과 같다.
각각의 파일 내용도 필요한 부분만을 남겨준다.
// index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<App />,
document.getElementById("root")
);
// App.js
function App() {
return <div className="App"></div>;
}
export default App;
이제 프로젝트가 정상적으로 작동하는지 확인해보자.
고리타분하지만 개발의 첫 시작에 빠질 수 없는 문장인 “Hello World”를 화면에 표시할 것이다.
// App.js
function App() {
return <div className="App"> Hello World! </div>;
}
App.js
를 다음과 같이 바꿔주고, 터미널에 npm start
를 실행한다.
브라우저에 Hello World! 가 아주 선명하게 찍혀있는 걸 확인할 수 있다.
이제 redux-toolkit과 saga를 프로젝트에 셋팅해보자.
redux-toolkit과 saga 초기설정
우선, redux, redux-tookit, redux-saga 이 세가지를 npm을 통해 설치해야한다.
npm install redux @reduxjs/toolkit redux-saga
코드를 작성하기 전에, redux와 관련된 모든 코드를 넣을 폴더를 생성해준다. 여기서는 redux
라는 이름의 폴더를 만들어주었다.
이 redux 폴더 안에서 코드를 나누는 방법은 다양하지만, 본인은 기능별로 폴더를 나누는 방식을 선호하기 때문에 여기에서도 기능별로 나누겠다.
modal창을 띄우는 예제를 만드는 중이었기 때문에 modal
이라는 폴더를 생성한 후 그 안에 slice.js
와 saga.js
파일을 각각 생성해준다.
redux slice 만들기
// slice.js
import { createSlice } from '@reduxjs/toolkit';
// 초기 state
const initialState = {
};
// slice
const modal = createSlice({
name: 'modal',
initialState,
reducers: {
openModal : (state, action) => {
},
closeModal : (state, action) => {
}
}
});
export const { openModal, closeModal } = modal.actions;
export const modalReducer = modal.reducer;
* redux-toolkit의 createSlice
는 초기 상태값, 액션, 리듀서를 하나의 객체에 담아 전달받는다.
saga 만들기
// saga.js
import { createAction } from "@reduxjs/toolkit";
import { takeLatest } from "redux-saga/effects";
export const deleteSomething = createAction("modal/deleteSomething");
function* deleteSaga() {
try {
yield console.log(" connect saga...");
} catch (error) {}
}
export function* modalSaga() {
yield takeLatest(deleteSomething, deleteSaga);
}
deleteSomething
이라는 액션이 발생하면, deleteSaga
제너레이터를 실행해준다.
* redux-saga
의 takeLatest
는 가장 마지막으로 발생한 액션에 대해서만 응답한다.
그리고 index.js
export * from "./slice";
export * from "./saga";
modal/index.js 파일 안에는 위와 같이 작성한다.
디렉토리 별로 index 파일을 만들어주면 여러 이점이 있는데, 그 중 하나는 다른 파일에서 slice나 saga를 import시 import * from '../modal/slice'
가 아닌 'import * from '../modal'
로 경로를 줄여서 작성할 수 있다는 점이다.
루트 reducer 만들기
프로젝트가 커질수록 📁redux
폴더 안에는 기능별로 분류된 많은 양의 slice와 saga들이 존재할 것이다. 이들을 통틀어 관리하는 루트 Reducer를 생성해줘야한다.
📁redux
폴더에 index.js
를 생성해준다.
import { configureStore } from '@reduxjs/toolkit';
import { modalReducer } from './modal';
const store = configureStore({ reducer: modalReducer});
루트 saga 만들기
루트 saga 또한 redux/index.js 파일 내에 만들어준다.
import createSagaMiddleware from 'redux-saga';
import { all } from 'redux-saga/effects';
import { modalReducer, modalSaga } from './modal';
const sagaMiddleware = createSagaMiddleware();
// root saga 정의
const rootSaga = function* () {
yield all([ modalSaga() ]);
};
// saga 실행
sagaMiddleware.run(rootSaga);
createSagaMiddleware
를 통해 saga 미들웨어 인스턴스를 생성해준다.
* redux-saga
의 all
함수는 여러 사가를 합쳐주는 역할을 한다.
export const store = configureStore({
reducer: modalReducer,
middleware: [sagaMiddleware],
});
앞서 만든 store에 sagaMiddleware
를 연결시켜준다.
/ redux/index.js
import { configureStore } from "@reduxjs/toolkit";
import createSagaMiddleware from "@redux-saga";
import { modalReducer, modalSaga } from "./modal";
import { all } from "redux-saga/effects";
const sagaMiddleware = createSagaMiddleware();
const createStore = () => {
const store = configureStore({
reducer: modalReducer,
middleware: [sagaMiddleware],
});
const rootSaga = function* () {
yield all([modalSaga()]);
};
sagaMiddleware.run(rootSaga);
return store;
};
export default createStore;
전체적인 코드는 위와 같다.
이제 최상위의 index.js
에 store를 연결해준다.
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import App from "./App";
import createStore from "./redux";
const store = createStore();
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
이렇게 초기 설정이 끝났다.
여기에 나온 코드는 정말 필요한 뼈대만을 연결해준 거고, 이제 프로젝트를 진행하면서 필요한 것들을 하나씩 붙여나가면 된다.