리덕스 모듈 만들기

정영찬·2022년 3월 14일
0

리액트

목록 보기
52/79
post-custom-banner

리덕스 모듈이란,

  • 액션 타입
  • 액션 생성함수
  • 리듀서
    이 세가지가 모두 들어있는 자바스크립트 파일을 뜻한다.

액션과 리듀서를 따로 작성하는 경우가 있지만, 이번 실습에서는 한 파일에 몰아서 작성한다.
이때 사용하는 패턴을 Ducks패턴이라고 하는데, ducks패턴은 리듀서와 액션관련 코드들을 하나의 파일에 몰아서 작성하는 방식이다.

루트 리듀서 만들기

counter.jstodos.js를 작성한다.

const SET_DIFF = 'counter/SET_DIFF';
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';


//액션 생성함수

export const setDiff = diff => ({ type: SET_DIFF, diff});
export const increase = () => ({ type:INCREASE});
export const decrease = () => ({type:DECREASE});

// 초기상태
const initialState = {
    number: 0,
    diff: 1
};


// 리듀서 선언
export default function counter(state = initialState, action){
    switch(action.type){
        case SET_DIFF:
            return{
                ...state,
                diff: action.diff
            };
        case INCREASE:
            return{
                ...state,
                number: state.number + state.diff
            }
        case DECREASE:
            return{
                ...state,
                number: state.number - state.diff
            }
        default:
            return state;
    }
}
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';

//액션 생성함수 

let nextId = 1;

export const addTodo = text => ({
    type: ADD_TODO,
    todo: {
        id: nextId++,
        text
    }
});
export const toggleTodo = id => ({
    type: TOGGLE_TODO,
    id
});


//초기상태

const initialState = [
   /*  {
        id: 1,
        text:"어서오고",
        done: false
    } */
];

export default function todos(state=initialState, action){
    switch(action.type) {
        case ADD_TODO:
            return state.concat(action.todo);

        case TOGGLE_TODO:
            return state.map(
                todo =>
                todo.id === action.id // id 일치하면
                ?{...todo, done: !todo.done}
                : todo
            );
        default:
            return state;
    }
}

이 두개의 리듀서를 합친 루트 리듀서를 제작한다. combineReducers를 이용한다.
index.js를 생성한다.

import {combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';


const rootReducer = combineReducers ({
    counter,
    todos
});


export default rootReducer;

todos의 경우 이전에 만들었던 todolist 프로젝트에 리덕스를 적용할 수 있는데 그렇게 하려면 먼저 react-redux를 설치해야한다.

그 다음 루트 경로의 index.js에 Provider, createStore, rootReducer를 불러와서
rootReducer가 들어있는 스토어 store를 생성한뒤 콘솔 로그로 출력시켜보자.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import rootReducer from './modules';


const store = createStore(rootReducer);
console.log(store.getState());

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

콘솔 화면에

이렇게 2개의 리듀서가 나타난다.

리듀서를 리액트 프로젝트에 적용시키는 방법은 index에서 AppProvider에 감싼다. 이때, Provider의 값에 store를 추가시킨다.


ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

카운터 구현하기

프리젠테이셔널 컴포넌트 만들기

리덕스 스토어에 직접적으로 접근하지 않고 필요한 값 또는 함수를 props 로만 받아와서 사용하는 컴포넌트이다.

import React from "react";

function Counter({number, diff, onIncrease, onDecrease, onSetDiff}) {
    const onChange = e => {
        onSetDiff(parseInt(e.target.value, 10));
    }
    return (
        <div>
            <h1>{number}</h1>
            <div>
                <input type="number" value={diff} min="1" onChange={onChange}></input>
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>
            </div> 
        </div>
    );
}

export default Counter;

전반적으로 UI선언에 집중하고 필요한 값을 props로 받아와서 사용한다.

컨테이너 컴포넌트 만들기

리덕스 스토어 상태조회, 액션을 디스패치 할수 있는 컴포넌트를 뜻한다. HTML태그를 사용하지않고, 다른 프레진테이셔널 컴포넌트들을 불러와서 사용한다.

import React from "react";
import {useSelector, useDispatch} from 'react-redux';
import Counter from '../components/Counter';
import { increase, decrease, setDiff} from '../modules/counter';

function CounterContainer() {
    const {number,diff} = useSelector(state => ({
        number: state.counter.number,
        diff: state.counter.diff
    }));

    const dispatch = useDispatch();
    const onIncrease = () => dispatch(increase());
    const onDecrease = () => dispatch(decrease());
    const onSetDiff = diff => dispatch(setDiff(diff));

    
    return (
       <Counter
       number={number}
           diff={diff}

           onIncrease={onIncrease}
           onDecrease={onDecrease}
           onSetDiff={onSetDiff}
        />
           

    );
}

export default CounterContainer;

App에 CounterContainer컴퍼넌트를 추가하고 실행해보면

이렇게 입력한 숫자만큼 더해지는 모습을 볼수 있다.

profile
개발자 꿈나무
post-custom-banner

0개의 댓글