Skip to content
Home » 리액트 리덕스 예제 | React 입문자들이 알아야할 Redux 쉽게설명 (8분컷) 14620 명이 이 답변을 좋아했습니다

리액트 리덕스 예제 | React 입문자들이 알아야할 Redux 쉽게설명 (8분컷) 14620 명이 이 답변을 좋아했습니다

당신은 주제를 찾고 있습니까 “리액트 리덕스 예제 – React 입문자들이 알아야할 Redux 쉽게설명 (8분컷)“? 다음 카테고리의 웹사이트 sk.taphoamini.com 에서 귀하의 모든 질문에 답변해 드립니다: sk.taphoamini.com/wiki. 바로 아래에서 답을 찾을 수 있습니다. 작성자 코딩애플 이(가) 작성한 기사에는 조회수 53,754회 및 좋아요 1,559개 개의 좋아요가 있습니다.

Table of Contents

리액트 리덕스 예제 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 React 입문자들이 알아야할 Redux 쉽게설명 (8분컷) – 리액트 리덕스 예제 주제에 대한 세부정보를 참조하세요

React 하다보면 Redux를 필히 만나게 되는데
한 해 리덕스 포기자가 10만명이나 되기 때문에 준비했습니다

리액트 강의 https://codingapple.com/course/react-basic/
구독자용 10% 할인코드 : YT123 (맨날 바뀜 최근영상 참고)
BGM : Dragonfruit Salad https://soundcloud.com/lacheque/dragonfruit

리액트 리덕스 예제 주제에 대한 자세한 내용은 여기를 참조하세요.

[React] 리덕스 총정리 및 예제 – 코딩병원

[React] 리덕스 총정리 및 예제. 코딩병원 2022. 3. … 이러한 Redux는 가장 많이 사용하는 리액트 상태 관리 라이브러리입니다. Redux를 사용하면 …

+ 더 읽기

Source: itprogramming119.tistory.com

Date Published: 1/9/2022

View: 3438

(React-Redux) 리액트 리덕스를 이용한 간단한 프로젝트 및 설명

react-redux: 리액트 환경 맞는 리덕스를 사용할 수 있게 해줌. … to log results (for example: reportWebVitals(console.log)) // or send to an …

+ 더 읽기

Source: eunhee-programming.tistory.com

Date Published: 2/13/2021

View: 7924

[React.js] #7 Redux(리덕스) 따라해보기! – 탕구리’s 블로그

이번 포스팅에서는 간단한 예제들을 따라 해 보며 리덕스에 조금 더 … 리액트에서는 이전 상태와 액션을 통해 다음 상태를 반환하는 순수 함수로 …

+ 여기에 더 보기

Source: real-dongsoo7.tistory.com

Date Published: 9/24/2022

View: 206

Redux의 흐름과 예제 – ivorycode

1. useDispatch 는 리덕스 스토어의 dispatch를 함수에서 사용할 수 있게 해주는 react-redux에서 제공하는 hook이다. 이것을 이용하여 각각의 액션들을 …

+ 더 읽기

Source: ivorycode.tistory.com

Date Published: 1/5/2022

View: 450

1. 리덕스 프로젝트 준비하기 · GitBook

리덕스 미들웨어를 공부해보기 전에, 리덕스 프로젝트를 먼저 새로 생성해주도록 하겠습니다. … redux react-redux. 이제, 카운터 예제를 만들어보도록 하겠습니다.

+ 여기를 클릭

Source: react.vlpt.us

Date Published: 2/26/2021

View: 5547

[React/Redux] 리액트 리덕스 사용해보기 – 밤의 공간

일반 리액트앱에 리덕스를 이용하면 상태 관리 로직을 따로 만들고 관리 … 그리고 이것으로 리덕스를 이용한 앱의 상태 변화 예제를 마치겠습니다.

+ 더 읽기

Source: bamtory29.tistory.com

Date Published: 6/27/2021

View: 6834

[Redux] 간단한 예제로 살펴보는 리덕스의 동작 원리 – 개발계발

React 는 상태를 기반으로 사용자 인터페이스( UI )를 제어하기 위한 자바스크립트 라이브러리이다. 웹 애플리케이션은 사용자와의 활발한 인터렉션을 …

+ 여기에 보기

Source: pebblepark.tistory.com

Date Published: 8/25/2021

View: 378

예제를 통해 리덕스(redux)를 연습해봅시다.

redux와 react-redux를 다운받을 수 있습니다. 해당 모듈들을 다운로드 했다면 이제 리덕스 폴더를 만들어보도록 하겠습니다. src/reducers/index.js 파일 …

+ 여기를 클릭

Source: justmakeyourself.tistory.com

Date Published: 6/25/2022

View: 8370

주제와 관련된 이미지 리액트 리덕스 예제

주제와 관련된 더 많은 사진을 참조하십시오 React 입문자들이 알아야할 Redux 쉽게설명 (8분컷). 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

React 입문자들이 알아야할 Redux 쉽게설명 (8분컷)
React 입문자들이 알아야할 Redux 쉽게설명 (8분컷)

주제에 대한 기사 평가 리액트 리덕스 예제

  • Author: 코딩애플
  • Views: 조회수 53,754회
  • Likes: 좋아요 1,559개
  • Date Published: 2021. 9. 13.
  • Video Url link: https://www.youtube.com/watch?v=QZcYz2NrDIs

(React-Redux) 리액트 리덕스를 이용한 간단한 프로젝트 및 설명

반응형

리액트 리덕스를 이용한 간단한 프로젝트

리덕스를 사용하여 간단한 프로그램을 제작하면서,

리덕스를 더욱 잘 이해하기위해 포스팅을 제작하였습니다.

자료들을 참고하여 공부하며,

윗 쪽에는 버튼을 누르면 1씩 증가하게,

아랫쪽은, 제가 원하는 숫자를 넣으면, 그 숫자만큼 더해지는 프로그램을 제작하려고 합니다.

포스팅 요약

1. 프로그램을 만들기전 간단한 정리

2. 프로그램 만들기

3. 참고 포스팅 및 강의 링크들

1. 프로그램을 만들기전 간단한 정리

1) Provider란?

– Provider은 react-redux라이브러리 안에 있는 컴포넌트입니다.

– 리액트 앱에 스토어를 쉽게 연결하기 위한 컴포넌트 입니다.

2) combineReducer란?

– redux모듈이 제공하는 함수이다.

– 만든 모든 리듀서들을 통합하여 하나의 리듀서로 쓰기 위한 함수이다

3) useSelector란?

– redux의 state조회 (즉, 스토어에 있는 데이터들 조회)

4) useDispatch란?

– 생성한 action 실행

2. 프로그램 만들기

*counter, CounterContainers, Counter:

버튼 클릭시 1씩 증가 혹은 감소하는 프로그램을 위한 모듈과 컨테이너

*counter2, CounterContainers2, Counter2:

원하는 숫자 기입시, 기입한 숫자만큼 증가하는 프로그램을 위한 모듈과 컨테이너

1) 리액트 리덕스 실행

yarn add redux react-redux

혹은

npm install redux react-redux

react-redux: 리액트 환경 맞는 리덕스를 사용할 수 있게 해줌.

참고 링크: 리덕스 관련 npm 라이브러리 설치

2) Provider로 감싸기

file: src/index.js

import React from “react”; import ReactDOM from “react-dom”; import “./index.css”; import App from “./App”; import { createStore } from “redux”; import { Provider } from “react-redux”; import rootReducer from “./module/index”; const store = createStore(rootReducer); ReactDOM.render( , 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

3) 사용될 모듈 만들기

file: src/module/counter.js

* 버튼 클릭 시, ‘+’버튼 클릭시 1씩 증가, ‘-‘버튼 클릭시 1씩 감소

const INCREASE = “counter/INCREASE”; const DECREASE = “counter/DECREASE”; export const increase = () => ({ type: INCREASE }); export const decrease = () => ({ type: DECREASE }); const initialState = 0; export default function counter(state = initialState, action) { switch (action.type) { case INCREASE: return state + 1; case DECREASE: return state – 1; default: return state; } }

file: src/module/counter2.js

* 버튼 클릭시, input에 적힌 숫자 만큼 증가

const INCREASE = “counter2/INCREASE”; const initialState = { value: 0, }; export const increase = (num) => ({ type: INCREASE, number: num, }); export default function counter2(state = initialState, action) { switch (action.type) { case INCREASE: return { …state, value: state.value + parseInt(action.number) }; default: return state; } }

4) combinereducer로 리듀서 함수들 통합하기

file: src/module/index.js

* 위 두개 모듈 하나로 통합해줌.

(모듈이 수억개라고 생각하면, combineReducers의 편리함을 알 수 있음. )

import { combineReducers } from “redux”; import counter from “./counter”; import counter2 from “./counter2”; const rootReducer = combineReducers({ counter, counter2 }); export default rootReducer;

5) 컨테이너 만들기

file: src/Containers/CounterContainers.js

import React from “react”; import Counter from “../components/Counter”; import { useSelector, useDispatch } from “react-redux”; import { increase, decrease } from “../module/counter”; const CounterContainers = () => { const number = useSelector((state) => state.counter); const dispatch = useDispatch(); const onIncrease = () => { dispatch(increase()); }; const onDecrease = () => { dispatch(decrease()); }; return ( ); }; export default CounterContainers;

file: src/Containers/CounterContainer2.js

import React from “react”; import Counter2 from “../components/Counter2”; import { useSelector, useDispatch } from “react-redux”; import { increase } from “../module/counter2”; const CounterContainer2 = () => { const number2 = useSelector((state) => state.counter2); const dispatch = useDispatch(); const onIncrease2 = (num) => { dispatch(increase(num)); }; return ; }; export default CounterContainer2;

6) 화면에 보여줄 컴포넌트

file: src/components/Counter.js

import React from “react”; const Counter = ({ number, onIncrease, onDecrease }) => { return (

{number}

); }; export default Counter;

file: src/components/Counter2.js

import React, { useState } from “react”; const Counter2 = ({ number2, onIncrease2 }) => { const [num, setNum] = useState(0); const onChange = (e) => { setNum(e.target.value); }; return (


CounterContainer2

DisplayNum

{number2}

); }; export default Counter2;

7) App에 컨테이너 넣기

import React from “react”; import CounterContainers from “./Containers/CounterContainers”; import CounterContainer2 from “./Containers/CounterContainer2”; const App = () => { return (

); }; export default App;

8) 결과

– 이미지 화면

– 영상

3. 참고 포스팅 및 강의 링크들

– 강의

유튜브 생활코딩님 강의

– 참고 블로그

https://react.vlpt.us/redux-middleware/01-prepare.html

* 이 블로그에서 배울게 매우 많습니다.

반응형

[React.js] #7 Redux(리덕스) 따라해보기!

반응형

지난 포스팅에서 리덕스에 대한 내용을 간단히 알아보았습니다.

이번 포스팅에서는 간단한 예제들을 따라 해 보며 리덕스에 조금 더 익숙해지는 시간을 가져보도록 합시다.

지난 포스팅에서 리덕스의 세 가지 핵심 개념에 대해서 언급했었는데요.

가장 먼저 액션에 대해서 알아봅시다.

액션은 애플리케이션에서 스토어로 보내는 데이터 묶음입니다. 이들이 스토어의 유일한 정보원이 됩니다.

여러분은 store.dispatch()를 통해 이들을 보낼 수 있습니다.

라고 나와 있습니다.

액션이 생성되면 상태가 변화될 때 dispatch를 통해 reducer로 보내주게 되는 구조라고 언급했었습니다. 액션을 다루면서 해주어야 할 작업은 “액션 타입 선언”과 “액션 생성 함수”를 만들어 주는 것입니다.

액션 타입 선언

# 액션 타입 const INCREMENT = ‘counter/INCREMENT’; const DECREMENT = ‘counter/DECREMENT’; # 액션 { type: INCREMENT, text: ‘hello world’ } { type: DECREMENT }

액션을 선언하는 방법은 어렵지 않습니다.

액션은 자바스크립트 객체입니다. type을 반드시!! 포함해야 하고 이외의 부분은 마음대로 정의하면 된다고 합니다.

액션은 스토어에 데이터를 넣을 수 있는 유일한 방법이기 때문에 어떤 방식을 사용하더라도 최종적으로는 액션을 통해 스토어에 전달됩니다.

액션 생성자

function increse(value) { return { type: INCREMENT, value } } const increse = (value) => ({ type: INCREMENT, value })

액션 생성자는 우리가 위에서 만들었던 액션이 실제도 동작할 수 있도록 도와주는 함수입니다.

이렇게 액션 생성자를 생성한 후 dispatch를 통해 reducer로 전달시켜 상태(state)와 액션(action)을 조합하는 과정이 진행됩니다.

dispatch(increment(value)) dispatch(decrement(value))

요로코롬 액션 생성자를 디스패치 시켜줄 수 있습니다.

액션 다루기

액션을 다루기 위해서는 reducer를 사용해야 합니다. 제가 처음 reducer 함수를 접했을 때는 이해가 잘 안 갔었는데, 진짜 간단하게 이야기하면 “파라미터를 조합하여 하나의 결과물로 만든다.” 정도로 이해하고 있었습니다.

리액트에서는 이전 상태와 액션을 통해 다음 상태를 반환하는 순수 함수로 이해하시면 좋을 것 같습니다.

(previousState, action) => newState

그리고 한번 더 말씀드리지만 “리듀서는 순수 함수”여야 합니다.

export default function reducer(state = initalState, action) { switch(action.type) { case INCREMENT: return { number: state.number+1 } case DECREMENT: return { number: state.number-1 } default: return state } }

문서에서는 swtich문을 선호하지는 않는 것 같습니다. switch문 외에도 여러 가지 방법이 있으니 차차 알아가 보도록 하겠습니다.

카운트 값을 조작하는 액션 외에도 생뚱맞지만 로그인 여부를 구분하는 액션도 있다고 가정해 봅시다.

export const LOG_IN = ‘log/IN’ export const LOG_OUT = ‘log/OUT’ export const INCREMENT = ‘counter/INCREMENT’; export const DECREMENT = ‘counter/DECREMENT’; const initialState = { isLogged : true, number : 0 } export const login = () => ({ type: LOG_ON }) export const logout = () => ({ type: LOG_OUT }) export const increase = (value) => ({ type: INCREMENT }) export const decrease = (value) => ({ type: DECREMENT }) export default function reducer(state = initalState, action) { switch(action.type) { case INCREMENT: return { number: state.number+1 } case DECREMENT: return { number: state.number-1 } case LOG_IN: return { isLogged : true } case LOG_OUT: return { isLogged : false } default: return state } }

이렇게 전혀 연관성이 없는 increase와 decrease 그리고 login과 logout이 하나의 리듀서에 있습니다. 지금은 굉장히 단순한 로직을 담고 있지만 코드가 복잡해지게 된다면 관리하기 굉장히 불편하고 가독성이 떨어집니다. 그래서 리듀서를 각각 분리하여 관리할 수 있도록 수정해 보겠습니다.

function counter(state, action) { switch(action.type) { case INCREMENT: return state+1 case DECREMENT: return state-1 defualt: return state } } function logged( state, action) { switch(action.type) { case LOG_IN: return true case LOG_OUT: return false default: return false } } export default function reducer(state = initalState, action) { return { counter : counter(state.number, action), isLogged: logged(state.isLogged, action) } }

이렇게 하나의 리듀서를 용도에 따라 여러 개로 분리할 수 있고 여러 개의 리듀서를 하나의 리듀서로 합칠 수도 있습니다.

또한, 리덕스는 보일러 플레이트 로직을 지원하는 combineReducers()라는 유틸리티를 제공합니다. conbineReducers()를 활용하면 다음과 같이 재작성할 수 있습니다.

import { combineReducers } from ‘redux’; const counter_logged = combineReducers({ counter, logged }); export defualt counter_logged ===========================같은 코드 입니다=========================== export default function reducer(state = initalState, action) { return { counter : counter(state.number, action), isLogged: logged(state.isLogged, action) } }

이번 포스팅에서는 액션과 액션 생성자를 만들어보고 이후 리듀서를 조작해보는 부분까지 간단한 예제를 만들어 보면서 정리해보았는데 여러 번 보다 보니 어느정도 이해는 가는데 아직 손에 그렇게 익은 상태는 아닌 것 같아요. 앞으로도 계속 하나씩 따라 해 가며 기초를 탄탄하게 다져보도록 하겠습니다.

저의 포스팅은 주관적인 내용이 상당히 많이 존재합니다.

그렇기 때문에 설명이 잘못되거나 모자란 부분이 존재할 수 있음을 양해하여 읽어주시면 감사하겠습니다.

탕빠이!

반응형

Redux의 흐름과 예제

반응형

Redux의 3가지 원칙

1. 하나의 애플리케이션 안에는 하나의 스토어만 사용하자.

특정 업데이트가 빈번하게 일어나거나, 애플리케이션 특정 부분을 분리시키게 되면, 여러 개의 스토어를 사용할 수 있다, 하지만, Redux는 하나의 애플리케이션에서 여러 개의 스토어 사용을 권장하지 않는 이유는 개발 도구를 활용하지 못하게 되어 디버깅이 어려워지기 때문이다. 그러니 하나의 스토어만 사용하여 디버깅을 용이하게 하고, 서버와의 직렬화를 통해 클라이언트에서 데이터를 쉽게 받아올 수 있도록 한다.

2. state는 읽기 전용이다.

Redux는 state를 변경할 때, 기존 값은 건드리지 않고, action을 일으켜 새로운 state를 생성하여 업데이트해주는 방식이다. 이것은 Redux 고유의 불변성을 지키고, state를 변경하려는 의도를 파악하고 디버깅을 용이하게 한다.

3. Reducer는 순수 함수여야 한다.

변화를 일으키는 Reducer는 반드시 순수 함수여야 한다. 순수 함수가 다음 조건을 만족해야 한다.

Reducer 함수는 이전 state와 action 객체를 parameter로 받는다.

parameter외의 값에 의존해선 안된다.

이전 state는 건드리지 않고, 변화를 준 새로운 state 객체를 만들어서 리턴한다.

같은 parameter로 호출된 Reducer 함수는 언제나 같은 결과를 리턴해야 한다.

Redux Flow

지금부터 아래의 이미지와 함께 Redux의 전체 흐름에 대해 정리해보자.

Redux Flow 이미지 출처: www.google.com

초기 상태

– store에서 reducer를 호출하고 리턴 값을 초기로 상태로 저장한다.

– UI가 최초 렌더링 될 때, UI 컴포넌트는 store의 state에 접근하여 렌더링에 활용한다. 그리고 그 state가 업데이트되는 것을 subscribe 한다.

Flow(업데이트) 순서

Deposit $10 버튼을 클릭한다. dispatch 함수를 실행시켜 action을 일으킨다. store에선 이전 state와 현재의 action으로 reducer함수를 실행하고, 리턴된 값을 새로운 state로 저장한다. store에서 store를 subscribe하고 있던 UI 컴포넌트들 에게 업데이트 여부를 알린다. store의 데이터가 필요한 각각의 컴포넌트들은 state가 업데이트되었는지 확인한다. 데이터가 변경된 요소들은 새로운 데이터로 강제 리렌더링 되므로화면에 표시되는 내용을 업데이트할 수 있다.

Counter 예제 만들어보기

카운터 예제를 통해 Redux를 직접 활용해보도록 하자!! 참고로 React를 활용하여 Redux를 적용해볼 계획이니, 이점 반드시 참고하길 바랍니다!!

# 프로젝트 생성

# react 프로젝트 생성 npx create-react-app redux_counter

# 리덕스 설치하기

# redux 설치하기 # NPM npm install redux # Yarn yarn add redux # react-redux 설치하기 # react에서 redux를 사용하려면 redux와 react-redux 모두 설치해줘야 한다. # NPM npm install react-redux # Yarn yarn add react-redux

# 폴더 구조

Ducks 패턴을 적용한 예제

예전엔 src 폴더에 store(또는 module)라는 디렉토리를 생성해서 그 안에 action, reducer, type이라는 디렉토리를 생성하고 각각에 맞는 Redux파일을 작성했었다. 그러나 하나의 기능을 수정하려고 하면, 해당 기능과 관련된 여러 개의 파일을 수정해야 하는 일이 발생하는데, 이러한 불편함을 개선하고자 나온 것이 Ducks 패턴이다. Ducks 패턴은 구조 중심이 아니라 기능중심으로 파일을 나누기 때문에 단일 기능을 작성할 때나 기능을 수정할 때 하나의 파일만 다루면 되므로 직관적인 코드 작성이 가능하다. 폴더구조는 개인 또는 프로젝트마다 관리하는 방법이 다르므로 정답은 없다. 그 외 나머지는 CRA 폴더 구조와 동일하다.

1. action type, action creator 생성

src/store/modules/counter.js

// Actions const INCREMENT = “INCREMENT”; const DECREMENT = “DECREMENT”; // Action Creator export const increment = () => { return { type: INCREMENT, }; } export const decrement = () => { return { type: DECREMENT, }; }

1. 카운터에 필요한 +, – 2가지 액션을 만들어 준다. 이때, 타입명은 중복이 되지 않도록 작성한다.

2. 다음은 액션 생성 함수를 만들어 주면 되는데, 이때 액션 생성 함수는 나중에 컴포넌트에서 사용될 함수이므로 export 키워드를 반드시 붙여준다.

🆘 액션(action)

state에 변화를 일으킬 때 참조하는 객체

2. reducer 생성

src/store/modules/counter.js

// 초기값 설정 const initialState = { number: 0, }; // counterReducer export default function counter(state = initialState, action) { switch (action.type) { case INCREMENT: return { number: state.number + 1, }; case DECREMENT: return { number: state.number – 1, }; default: return state; } }

1. 카운터에 적용될 초기값을 설정해준다. 보통 initialState라고 선언한다.

2. 리듀서를 만들어준다. parameter에 초기 state를 넣어주고, 액션 객체를 넣어준다. 그리고 switch문으로 액션이 발생했을 때의 값을 리턴하도록 작성한다. 어떠한 액션도 발생하지 않았을 때를 대비하여 default도 반환해준다.

(리듀서 앞에 export 키워를 붙여서 선언한 것을 확인할 수 있는데, 그 이유는 아래에서 설명하도록 하겠다.)

🆘 리듀서(reducer)

state에 변화를 일으키는 함수. 리듀서는 parameter를 두 개 받는다. 첫 번째는 현재 state(초기값), 두 번째는 액션 객체를 받는다.

3. combineReducer 생성

Redux 내장함수엔 combineReducer라는 기능이 있다. 단어 그대로 모든 리듀서들을 합치는 기능이다. 지금은 비록 카운터 기능 하나뿐이라 리듀서를 합칠 필요가 없지만, 나중에 프로젝트를 진행하다 보면 여러 가지 리듀서가 생성될 것이고, 이것을 하나하나씩 연결한다는 것은 비효율적이므로 알아두면 도움이 많이 되고 복잡하지 않으니 바로 다뤄보자!!

src/store/modules/index.js

import { combineReducers } from “redux”; import counter from “./counter”; // import한 리듀서 이름을 그대로 사용하는 경우 export default combineReducers({ counter, }); // 리듀서 이름을 지정하는 경우 export default combineReducers({ // 리듀서 이름: import한 리듀서 counterData: counter, });

1. combineReducers와 위에서 export했던 counter 리듀서를 import 해준다.

2. 리듀서를 합쳐주는 방법은 리듀서 이름을 그대로 사용하는 경우, 직접 지정하는 경우 이렇게 2가지가 있다.

4. Counter Component 생성

1, 2, 3 과정을 통해 Redux 파일 구조를 생성해봤다. 그런데 파일을 활용할 곳이 없으니 간단하게 컴포넌트를 만들어 View화면을 만들어주도록 하자.

src/components/Counter.js

import { useDispatch, useSelector } from “react-redux”; import { decrement, increment } from “../store/modules/counter”; export default function Counter() { const dispatch = useDispatch(); // import한 리듀서 이름을 그대로 사용하는 경우 const count = useSelector((state) => state.counter.number); // 리듀서 이름을 지정하는 경우 // const count = useSelector((state) => state.counterData.number); return (

COUNTER

{count}

); }

1. useDispatch 는 리덕스 스토어의 dispatch를 함수에서 사용할 수 있게 해주는 react-redux에서 제공하는 hook이다. 이것을 이용하여 각각의 액션들을 dispatch 해준다.

2. useSelector는 리덕스 스토어의 state를 조회하는 hook이다. 위의 코드를 잠시 살펴보면 state.counter.number에서 counter는 방금 전 생성한 리듀서의 이름을 말한다.

🆘 디스패치(dispatch)

dispatch 함수는 액션 객체를 넘겨줘서 state를 변경할 수 있는 함수다.

5. Component 연결

src/App.js

import logo from “./logo.svg”; import “./App.css”; import Counter from “./components/Counter”; function App() { return (

logo

Study Redux

); } export default App;

1. App.js 파일에 카운터 컴포넌트를 import 해준다.

6. Store 생성

src/index.js

하나의 애플리케이션엔 하나의 스토어가 존재한다. 스토어 안에는 state를 담고 있고, 업데이트될 때마다 다시 실행하게 한다.

import React from “react”; import ReactDOM from “react-dom”; import “./index.css”; import App from “./App”; import { createStore } from “redux”; import { Provider } from “react-redux”; import rootReducer from “./store/modules”; const store = createStore(rootReducer); ReactDOM.render( , document.getElementById(“root”) );

1. createStore를 생성하여 위의 과정에서 만든 리듀서를 parameter에 넣어준다. 만들어둔 combineReducer가 있으니 그것을 활용해보자.

2. Provider는 react-redux에서 제공하는 컴포넌트로 리액트 프로젝트에 store를 쉽게 연동할 수 있도록 하는 컴포넌트다. Provider를 불러온 후, props에 아까 선언했던 store를 넣어주자.

# 프로젝트 실행

위의 과정을 모두 진행했으니 이제 프로젝트를 실행시켜서 확인해보자!!

# NPM npm start # YARN yarn start

Success!!

위의 이미지과 같게 나온다면 성공!!!

GitHub 예제 코드

– GitHub에 예제 코드를 공유하였습니다!! 같이 공부하고 공유하는 문화를 만들어 보고 싶습니다!!

– https://github.com/ivory-code/reduxExample.git

반응형

1. 리덕스 프로젝트 준비하기 · GitBook

1. 리덕스 프로젝트 준비하기

리덕스 미들웨어를 공부해보기 전에, 리덕스 프로젝트를 먼저 새로 생성해주도록 하겠습니다.

다음 명령어를 사용하여 새로운 프로젝트를 준비해주세요.

$ npx create-react-app learn-redux-middleware

이 섹션의 코드는 여기서 확인 가능합니다.

그리고 해당 디렉터리에서 redux와 react-redux를 설치해주세요.

$ cd learn-redux-middleware $ yarn add redux react-redux

이제, 카운터 예제를 만들어보도록 하겠습니다.

리덕스 모듈 준비

우리는 액션 타입, 액션 생성함수, 리듀서를 한 파일에 작성하는 Ducks 패턴을 사용하도록 하겠습니다. src 디렉터리에 modules 디렉터리를 만들고, 그 안에 counter.js 라는 파일을 생성해서 다음과 같이 작성해주세요.

원래 Ducks 패턴을 따르는 리덕스 모듈에서는 액션 이름에 ‘counter/INCREASE’ 이런식으로 앞부분에 접두어를 두지만, 이번에는 액션이름이 중복되는 일이 없으니, 편의상 생략하도록 하겠습니다.

modules/counter.js

const INCREASE = ‘INCREASE’ ; const DECREASE = ‘DECREASE’ ; export const increase = () => ({ type: INCREASE }); export const decrease = () => ({ type: DECREASE }); const initialState = 0 ; export default function counter ( state = initialState, action ) { switch (action.type) { case INCREASE: return state + 1 ; case DECREASE: return state – 1 ; default : return state; } }

그 다음에는 루트 리듀서를 만들어주세요. 물론 지금은 서브리듀서가 하나밖에 없는 상황이지만, 나중에 몇개 더 만들 것입니다.

modules/index.js

import { combineReducers } from ‘redux’ ; import counter from ‘./counter’ ; const rootReducer = combineReducers({ counter }); export default rootReducer;

프로젝트에 리덕스 적용

프로젝트에 리덕스를 적용해주세요. 프로젝트에 리덕스를 적용 할 때에는 src 디렉터리의 index.js 에서 루트리듀서를 불러와서 이를 통해 새로운 스토어를 만들고 Provider 를 사용해서 프로젝트에 적용을 합니다.

index.js

import React from ‘react’ ; import ReactDOM from ‘react-dom’ ; import ‘./index.css’ ; import App from ‘./App’ ; import * as serviceWorker from ‘./serviceWorker’ ; import { createStore } from ‘redux’ ; import { Provider } from ‘react-redux’ ; import rootReducer from ‘./modules’ ; const store = createStore(rootReducer); ReactDOM.render( < Provider store = {store} > < App /> , document.getElementById(‘root’) ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();

프리젠테이셔널 컴포넌트 준비

그 다음, 프리젠테이셔널 컴포넌트 Counter 를 준비해주겠습니다. components 디렉터리에 Counter.js 파일을 만드세요. 해당 컴포넌트에서는 number, onIncrease, onDecrease를 props로 받아옵니다.

components/Counter.js

import React from ‘react’ ; function Counter ( { number, onIncrease, onDecrease } ) { return ( < div > < h1 > {number} < button onClick = {onIncrease} > +1 < button onClick = {onDecrease} > -1 ); } export default Counter;

컨테이너 만들기

그리고 컨테이너도 만들어줍시다.

containers/CounterContainer.js

import React from ‘react’ ; import Counter from ‘../components/Counter’ ; import { useSelector, useDispatch } from ‘react-redux’ ; import { increase, decrease } from ‘../modules/counter’ ; function CounterContainer ( ) { const number = useSelector(state => state.counter); const dispatch = useDispatch(); const onIncrease = () => { dispatch(increase()); }; const onDecrease = () => { dispatch(decrease()); }; return ( < Counter number = {number} onIncrease = {onIncrease} onDecrease = {onDecrease} /> ); } export default CounterContainer;

이제 App 에서 CounterContainer를 렌더링을 하고, yarn start 를 해서 개발 서버를 구동해보세요.

App.js

import React from ‘react’ ; import CounterContainer from ‘./containers/CounterContainer’ ; function App ( ) { return < CounterContainer /> ; } export default App;

이제 카운터가 작동하는지 확인해보세요.

이제 리덕스 미들웨어를 직접 만들어볼 준비가 끝났습니다.

[React/Redux] 리액트 리덕스 사용해보기

728×90

지난번에 리덕스에 대해 소개를 했으니 이번에는 리덕스를 간단하게 사용해볼 차례입니다. 일반 리액트앱에 리덕스를 이용하면 상태 관리 로직을 따로 만들고 관리가 가능해져, 프로젝트의 유지보수가 쉬워지고 다양한 편의 기능을 제공합니다.

리덕스, 리액트 리덕스를 설치해주세요.

yarn add redux

yarn add react-redux

1. 카운터/Todo 프로그램

우선 다음과 같은 카운터/Todo 기능이 있는 리액트 앱을 만들어줍니다.

import React from ‘react’; const ReduxCounter = ({number, onIncrease, onDecrease}) => { return (

{number}

); }; export default ReduxCounter;

import React from ‘react’; const TodoItem = ({todo, onToggle, onRemove}) => { return (

예제 텍스트

); }; const Todos = ({input, todos, onChangeInput, onInsert, onToggle, onRemove}) => { const onSubmit = e => e.preventDefault(); return (

); }; export default Todos;

import React from ‘react’; import ReduxCounter from ‘./codes/redux-tutorial/ReduxCounter’; import Todos from ‘./codes/redux-tutorial/Todos’; const App = () => { return (


); }; export default App;

2. 리덕스 코드 작성

2-1. 파일 구조

리덕스 코드를 정의할 때 action, action creator, reducer를 작성해야합니다. 그래서 이들을 작성할 때 actions, constants, reducers라는 디렉토리를 만들고 기능별로 작성하는 것이 공식적이고 기본적인 파일 구조입니다. 분류가 잘되어서 찾기 편하고 유지보수가 용이하다는 장점을 갖지만 action이 추가되는 경우 세 종류의 파일들을 모두 수정해야 하므로 번거로운 단점을 가지고 있습니다.

이런 단점을 해결하기 위한 방식이 Ducks 방식입니다. 위의 구조와 다르게 action, action creator, reducer를 하나의 디렉토리에서 작성하는 방식입니다. Ducks 방식을 이용해서 작성한 코드들은 ‘모듈’이라고 부르게 됩니다.

2-2. 카운터 프로그램의 모듈

우선 카운터 프로그램의 모듈부터 생성해보겠습니다. 가장 먼저 해야 할 일은 액션 타입의 정의입니다. 만든 모듈 파일 내부에 카운터 파일을 생성하고 다음과 같이 액션 타입을 정의합니다.

액션 타입은 대문자로 정의하고 문자열의 내용은 ‘모듈명/액션명’으로 표기합니다. 모듈명을 액션명 앞에 붙임으로써 중복 정의로 인한 충돌을 방지하게 됩니다.

const INCREASE = ‘reduxCounter/INCREASE’; const DECREASE = ‘reduxCounter/DECREASE’;

이어서 액션 생성 함수를 만들 차례입니다. increase 가 발생하면 INCREASE type 액션을 불러오고, decrease가 발생하게 되면 DECREASE type 액션을 생성하게 됩니다. 이때 액션 생성 함수는 외부에서 불러와 사용하기 위에 앞에 export 키워드를 붙입니다.

const INCREASE = ‘reduxCounter/INCREASE’; const DECREASE = ‘reduxCounter/DECREASE’; export const increase = () => ({ type: INCREASE, }); export const decrease = () => ({ type: DECREASE, });

마지막으로 카운터 모듈의 초기 상태와 리듀서 함수를 생성해보겠습니다.

초기 상태는 카운터가 0부터 시작할 것이므로 0으로 주었습니다.

그리고 리듀서 함수는 default function parameter 문법으로 초기 상태를 기본 값으로 준 상태와 액션을 파라미터로 이용합니다.

const INCREASE = ‘reduxCounter/INCREASE’; const DECREASE = ‘reduxCounter/DECREASE’; export const increase = () => ({ type: INCREASE, }); export const decrease = () => ({ type: DECREASE, }); const initialState = { number: 0 }; function reduxCounter(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 reduxCounter;

모듈을 내보낼 때 action creator는 export로, reducer는 export default로 내보냈습니다. 두 방식의 차이점은 export는 여러 개를 내보내고, export default는 단 한 개만을 내보낼 수 있습니다. 또 모듈을 불러올 때 export는 {}중괄호로 묶어서 불러오고, export default는 중괄호 없이 불러옵니다.

2-3. Todos 프로그램 모듈

이번엔 Todos의 모듈을 만들어볼 차례입니다. 마찬가지로 액션 타입부터 정의해보겠습니다. (끝나고 검수할 때 보니 파일명이 통일되지 않았습니다. 죄송합니다.)

const CHANGE_INPUT = ‘todos/CHANGE_INPUT’; const INSERT = ‘todos/INSERT’; const TOGGLE = ‘todos/TOGGLE’; const REMOVE = ‘todos/REMOVE’;

다음은 액션 타입에 따른 액션 생성 함수입니다.

const CHANGE_INPUT = ‘todos/CHANGE_INPUT’; const INSERT = ‘todos/INSERT’; const TOGGLE = ‘todos/TOGGLE’; const REMOVE = ‘todos/REMOVE’; export const changeInput = input => ({ type: CHANGE_INPUT, input, }); //todo의 id //다음 절에서 초기 상태에 2개를 넣을 예정이라 3으로 설정 let id = 3; 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 { //전개 연산자를 통한 deep copy로 불변성 유지 …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;

2-4. Root Reducer

reduxCounter와 todos, 두 개의 리듀서를 만들었습니다. 하지만 추후에 스토어를 만들기 위해서는 리듀서를 하나만 사용해야합니다. 그래서 이 두 개의 리듀서를 합치는 작업을 해야합니다. modules 디렉토리 내부에 index.js 파일을 만들어주세요.

여러개의 리듀서를 하나로 합쳐주는 일은 리덕스에서 제공하는 combineReducer를 이용합니다. 다음과 같이 작성하면 추후에 rootReducer 모듈 하나만 불러와도 여러개의 리듀서를 이용할 수 있게됩니다.

import {combineReducers} from ‘redux’; import reduxCounter from ‘./reduxCounter’; import todos from ‘./todos’; const rootReducer = combineReducers({reduxCounter, todos}); export default rootReducer;

3. 리액트 앱에 리덕스 적용하기

리액트 코드도 완성해뒀고, 리덕스 코드도 방금 작성을 완료했으니 이제는 리액트 앱에 리덕스 코드를 적용시킬 차례입니다. 리덕스 적용은 modules의 index.js가 아니라 src의 index.js에서 실행됩니다.

store를 생성하고 react-redux의 Provider 컴포넌트를 이용합니다. Provider 컴포넌트의 props로 생성한 store를 전달하면 됩니다.

import React from ‘react’; import ReactDom from ‘react-dom’; import {createStore} from ‘redux’; import {Provider} from ‘react-redux’; import ‘./index.css’; import App from ‘./App’; import rootReducer from ‘./codes/redux-tutorial/ducks-modules’; const store = createStore(rootReducer); ReactDom.render( , , document.getElementById(‘root’), ) ;

3-1. 리덕스 개발자 도구

이번에 소개할 것은 크롬의 확장 프로그램인 Redux DevTools입니다. 이 도구를 통해 상태나 추적 등을 할 수 있습니다.

https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/related?hl=ko

이 도구를 사용하기 위해서 스토어에 코드를 달아야 하는데요. redux-devtools-extension이라는 패키지를 통해 깔끔한 코드를 작성할 수 있습니다.

yarn add redux-devtools-extension

import React from ‘react’; import ReactDom from ‘react-dom’; import {createStore} from ‘redux’; import {Provider} from ‘react-redux’; import {composeWithDevTools} from ‘redux-devtools-extension’; import ‘./index.css’; import App from ‘./App’; import rootReducer from ‘./codes/redux-tutorial/ducks-modules’; const store = createStore(rootReducer, composeWithDevTools()); ReactDom.render( , , document.getElementById(‘root’), );

작성 후 개발자 도구를 열고 Redux 탭을 누릅니다. DevTool이 잘 표시가 된다면 성공한 것 입니다.

4. 컨테이너 컴포넌트

이제 적용까지 했으니 컴포넌트에서 조작을 하면 스토어에 접근해 상태를 받아오거나 디스패치하는 행동을 구현할 차례입니다. 이렇게 컴포넌트와 스토어를 연결한 컴포넌트를 컨테이너 컴포넌트라고 합니다.

4-1. 카운터 컨테이너 컴포넌트

다음 코드는 카운터 컴포넌트의 컨테이너 컴포넌트 입니다.

import React from ‘react’; import ReduxCounter from ‘../ReduxCounter’; const ReduxCounterContainer = () => { return ; }; export default ReduxCounterContainer;

만든 컨테이너 컴포넌트를 리덕스와 연결하기 위해서 react-redux 패키지의 connect 함수를 이용해야합니다.

connect(mapStateToProps, mapDispatchToProps)(타겟 컴포넌트);

mapStateToProps는 스토어의 State를 컴포넌트의 props로 넘기기 위한 함수입니다. mapDispatchToProps는 action creator를 컴포넌트의 props로 넘기기 위한 함수입니다. 타겟 컴포넌트는 연결할 컴포넌트를 넣으면 됩니다.

그러면 위에서 만든 컨테이너 컴포넌트를 connect로 연결해보겠습니다.

import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; const mapStateToProps = state => ({ number: state.reduxCounter.number, }); const mapDispatchToProps = dispatch => ({ increase: () => console.log(‘증가’), decrease: () => console.log(‘감소’), }); export default connect(mapStateToProps, mapDispatchToProps)(ReduxCounterContainer);

mapStateToProps의 state 파라미터는 현재 스토어의 state를 가리킵니다. 그리고 mapDispatchToProps의 파라미터인 dispatch는 store의 내장함수 dispatch를 파라미터로 받습니다. 이 두 함수가 반환하는 객체 값은 컴포넌트의 props로 전달되게 됩니다.

그리고 App.js의 카운터 컴포넌트를 지금 만든 카운터 컨테이너 컴포넌트로 변경해줍니다.

import React from ‘react’; import Todos from ‘./codes/redux-tutorial/Todos’; import ReduxCounterContainer from ‘./codes/redux-tutorial/containers/ReduxCounterContainer’; const App = () => { return (


); }; export default App;

이제 동작을 확인했으니 increase와 decrease 버튼을 누르면 카운터 숫자가 올라가도록 변경해보겠습니다. 액션을 발생시키는 store의 내장함수인 dispatch 부분만 변경하면 됩니다.

import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; import {decrease, increase} from ‘../ducks-modules/reduxCounter’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; const mapStateToProps = state => ({ number: state.reduxCounter.number, }); //증가 감소가 dispatch 되도록 const mapDispatchToProps = dispatch => ({ increase: () => dispatch(increase()), decrease: () => dispatch(decrease()), }); export default connect(mapStateToProps, mapDispatchToProps)(ReduxCounterContainer);

버튼을 누르면 카운터의 숫자가 변경됩니다. 그리고 reduxDevTool을 보면 상태 변화 기록을 볼 수 있습니다.

4-2. 리덕스 제공 기능으로 코드를 깔끔하게 만들기

리덕스는 전역 상태 관리 뿐 만 아니라 다양한 편의 기능도 제공한다고 알려드렸습니다. 그래서 완성된 컨테이너 컴포넌트를 편의 기능을 이용해서 간결한 코드로 변경해보겠습니다.

connect의 mapStateToProps와 mapDispatchToProps를 함수로 따로 선언하지 않고 내부에 익명 함수 형태로 선언하는 것 입니다. 이것은 리덕스 제공 방식 보다는 프로그래밍 스킬에 가까운 방식이긴 합니다. 이 방식을 이용하면 코드가 더 간결해집니다. (함수의 내용에 따라서 오히려 가독성을 해칠수가 있습니다.)

//변경 전 코드 import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; import {decrease, increase} from ‘../ducks-modules/reduxCounter’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; const mapStateToProps = state => ({ number: state.reduxCounter.number, }); const mapDispatchToProps = dispatch => ({ increase: () => dispatch(increase()), decrease: () => dispatch(decrease()), }); export default connect(mapStateToProps, mapDispatchToProps)(ReduxCounterContainer); //변경 후 코드 import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; import {decrease, increase} from ‘../ducks-modules/reduxCounter’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; export default connect( state => ({number: state.reduxCounter.number}), dispatch => ({ increase: () => dispatch(increase()), decrease: () => dispatch(decrease()), }) )(ReduxCounterContainer);

mapDispatchToProps에서 액션 함수들을 호출할 때 dispatch()로 감싸는 작업도 간단하게 줄일 수 있습니다. 리덕스에서 제공하는 bindActionCreators 함수를 이용하면 다음과 같이 간단하게 줄일 수 있습니다.

//bindActionCreators 사용 전 import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; import {decrease, increase} from ‘../ducks-modules/reduxCounter’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; export default connect( state => ({number: state.reduxCounter.number}), dispatch => ({ increase: () => dispatch(increase()), decrease: () => dispatch(decrease()), }) )(ReduxCounterContainer); //bindActionCreators 사용 후 import React from ‘react’; import {connect} from ‘react-redux’; import ReduxCounter from ‘../ReduxCounter’; import {decrease, increase} from ‘../ducks-modules/reduxCounter’; import {bindActionCreators} from ‘redux’; const ReduxCounterContainer = ({number, increase, decrease}) => { return ; }; export default connect( state => ({number: state.reduxCounter.number}), dispatch => bindActionCreators({ increase, decrease, }, dispatch, ), )(ReduxCounterContainer);

dispatch => bindActionCreators({ increase, decrease, }, dispatch, ),

dispatch 부분이 확실히 간단해진 것이 보이나요? 가독성 면에서도 저는 더 좋아졌다고 개인적으로 느꼈습니다.

여기서 한 번 더 간결한 구문을 작성할 수 있습니다. dispatch 파라미터 함수 대신 action creator로 구성된 객체를 넣어주면 더 간단한 표현이 가능합니다. 다음과 같이 액션 생성 함수로 이루어진 객체를 파라미터로 전달하면 내부적으로 위의 bindActionCreators와 같은 동작을 하게 됩니다.

export default connect( state => ({number: state.reduxCounter.number}), { increase, decrease, }, )(ReduxCounterContainer);

4-3. todos 컴포넌트 컨테이너

이제 todos 컴포넌트의 컨테이너를 만들어보겠습니다. 먼저 TodosContainer.js 컴포넌트입니다.

import React from ‘react’; import {connect} from ‘react-redux’; import {changeInput, insert, toggle, remove} from ‘../ducks-modules/todos’; import Todos from ‘../Todos’; const TodosContainer = ({input, todos, changeInput, insert, toggle, remove}) => { return ( ); }; export default connect( //todos 배열 비구조화 할당 state.todos.input을 간결하게 ({todos}) => ({ input: todos.input, todos: todos.todos, }), { changeInput, insert, toggle, remove, }, )(TodosContainer);

그리고 App.js의 Todos 컴포넌트를 컨테이너 컴포넌트로 변경합니다.

import React from ‘react’; import ReduxCounterContainer from ‘./codes/redux-tutorial/containers/ReduxCounterContainer’; import TodosContainer from ‘./codes/redux-tutorial/containers/TodosContainer’; const App = () => { return (


); }; export default App;

마지막으로 Todos 컴포넌트에서 컨테이너로부터 받아온 props를 사용할 수 있도록 코드를 작성해줍니다.

import React from ‘react’; const TodoItem = ({todo, onToggle, onRemove}) => { return (

onToggle(todo.id)} checked={todo.done} readOnly={true}/> {todo.text}

); }; const Todos = ({input, todos, onChangeInput, onInsert, onToggle, onRemove}) => { const onSubmit = e => { e.preventDefault(); onInsert(input); onChangeInput(”); }; const onChange = e => onChangeInput(e.target.value); return (

{todos.map(todo => ( ))}

); }; export default Todos;

이렇게 모든 상태 변화에 대해 리덕스 개발 도구에서 볼 수 있고 제대로 작동하는 것을 볼 수 있습니다. 그리고 이것으로 리덕스를 이용한 앱의 상태 변화 예제를 마치겠습니다.

중간에 끊기가 애매한 내용이라 한 큐에 가다보니 포스트 많이 길어졌습니다. 처음 접하면 다소 복잡하다고 생각될 수 있으므로 리덕스 기초 포스팅과 함께 읽어나가시길 추천드립니다.

참조

리덕스(Redux)를 왜 쓸까? 그리고 리덕스를 편하게 사용하기 위한 발악 (ii)

728×90

[Redux] 간단한 예제로 살펴보는 리덕스의 동작 원리

React 는 상태를 기반으로 사용자 인터페이스( UI )를 제어하기 위한 자바스크립트 라이브러리이다. 웹 애플리케이션은 사용자와의 활발한 인터렉션을 처리하고, 실시간 통신을 통해 데이터를 받아오며 이를 기반으로 렌더링을 하는 등 다양한 기능을 가지고 있다. 이때, 상태(state)를 관리하는 것은 필수적으로 요구되는 사항이다.

즉, 상태 관리란 React 앱 구축에 있어 핵심이 되는 부분 중 하나라 할 수 있다. 따라서 상태 관리를 위한 많은 기술이 다양한 라이브러리의 등장으로 이어지게 되었다. 그 중에서도 리덕스( Redux )는 리액트와 가장 오랜 기간을 함께했으며 가장 널리 알려진 상태관리 라이브러리 중 하나이다. 이번 포스팅에서는 리덕스의 동작 원리를 간단한 예제와 함께 살펴볼 것이다.

👉 리덕스의 코어 : createStore

약 25줄의 코드이지만 리덕스의 핵심 기능이 포함되어 있는 createStore 함수를 살펴보자.

createStore 에서는 현재 상태 값과 여러 구독자를 추적하고, 값을 업데이트하고, 작업이 전달될 때 구독자에게 알리고, 상태 값을 반환 받는 API를 가지고 있다.

function createStore(reducer) { var state; var listeners = []; function getState() { return state; } function subscribe(listener) { listeners.push(listener); return function unsubscribe() { var index = listeners.indexOf(listener); listeners.splice(index, 1); } } function dispatch(action) { state = reducer(state, action); listeners.forEach(listener => listener()); } dispatch({}); return { dispatch, subscribe, getState }; }

👉 하나씩 살펴보는 Redux Core

먼저, 스토어는 다음과 같은 값을 가지고 있다.

저장소에 저장할 상태 값 : state

상태 값을 구독하고 있는(변경을 감지) 구독자들을 저장하는 목록 : listeners 배열 해당 listner 들은 () => {} 형식의 콜백 함수 dispatch 함수가 호출될 때마다 실행된다.

배열

모든 상태 값은 하나의 저장소( store ) 안에 있는 객체 트리에 저장된다. 상태 트리를 변경하는 유일한 방법은 무엇이 일어날지 서술하는 객체인 액션( action )을 보내는 것 뿐이다. 액션이 상태 트리를 어떻게 변경할지 명시하기 위해 사용자는 리듀서( reducer )를 작성해야 한다.

function createStore(reducer) { var state; var listeners = []; // … }

getState()

getState 함수는 리덕스 저장소에 저장된 상태 값 state 를 반환한다.

function getState() { return state; }

subscribe(listener)

subscribe 함수는 상태값이 변경되었을 때 실행 될 콜백함수 listner 를 받아서 listners 배열에 추가한다. 해당 listner 를 listners 배열에서 삭제하는 구독 해지 함수 unscribe 를 반환한다.

function subscribe(listener) { listeners.push(listener); return function unsubscribe() { var index = listeners.indexOf(listener); listeners.splice(index, 1); } }

dispatch(action)

dispatch 함수는 action 을 받아서 reducer 함수를 통해 state 를 변경한다. 이후 listners 배열의 listner 를 하나씩 호출하면서 상태가 변경되었음을 알린다.

function dispatch(action) { state = reducer(state, action); listeners.forEach(listener => listener()); }

반환값

createStore 내부에서 dispatch({}) 를 호출함으로써 reducer 함수에서 action 이 빈 객체로 주어졌을 경우, 반환하는 값으로 state 를 초기화해준다. 이후 위에서 설명한 dispatch , subscribe , getState 함수를 담은 객체를 반환한다.

해당 함수들은 모두 클로저 함수이다. 따라서, createStore 에서 관리하는 값( state , listeners )은 외부에서 접근하지 못하며, 현재 상태를 기억하고 함수를 통해 상태가 변경되어도 최신 상태가 유지된다.

function createStore(reducer) { // … dispatch({}); return { dispatch, subscribe, getState }; }

👉 리덕스 기본 예제

리덕스의 동작 핵심 코드만 살펴보았을 때 이해가 잘 되지 않을 수도 있다. 따라서 아래 예제를 통해 다시 살펴보도록 하자.

import { createStore } from ‘redux’ /** * 이것이 (state, action) => state 형태의 순수 함수인 리듀서입니다. * 리듀서는 액션이 어떻게 상태를 다음 상태로 변경하는지 서술합니다. * * 상태의 모양은 당신 마음대로입니다: 기본형(primitive)일수도, 배열일수도, 객체일수도, * 심지어 Immutable.js 자료구조일수도 있습니다. 오직 중요한 점은 상태 객체를 변경해서는 안되며, * 상태가 바뀐다면 새로운 객체를 반환해야 한다는 것입니다. * * 이 예제에서 우리는 `switch` 구문과 문자열을 썼지만, * 여러분의 프로젝트에 맞게 * (함수 맵 같은) 다른 컨벤션을 따르셔도 좋습니다. */ function counter(state = 0, action) { switch (action.type) { case ‘INCREMENT’: return state + 1 case ‘DECREMENT’: return state – 1 default: return state } } // 앱의 상태를 보관하는 Redux 저장소를 만듭니다. // API로는 { subscribe, dispatch, getState }가 있습니다. let store = createStore(counter) // subscribe()를 이용해 상태 변화에 따라 UI가 변경되게 할 수 있습니다. // 보통은 subscribe()를 직접 사용하기보다는 뷰 바인딩 라이브러리(예를 들어 React Redux)를 사용합니다. // 하지만 현재 상태를 localStorage에 영속적으로 저장할 때도 편리합니다. store.subscribe(() => console.log(store.getState()))) // 내부 상태를 변경하는 유일한 방법은 액션을 보내는 것뿐입니다. // 액션은 직렬화할수도, 로깅할수도, 저장할수도 있으며 나중에 재실행할수도 있습니다. store.dispatch({ type: ‘INCREMENT’ }) // 1 store.dispatch({ type: ‘INCREMENT’ }) // 2 store.dispatch({ type: ‘DECREMENT’ }) // 1

Reducer 함수 : counter

counter 함수는 createStore 에 넘겨줄 reducer 함수이다.

action.type 의 값이 default 일 경우 state 를 반환하고 있다. 따라서 createStore 내부에서 dispatch({}) 를 실행하면 state 의 값이 0 으로 초기화 될 것이다.

이후 dispatch({type: ‘INCREMENT’}) 를 호출하면 state 값이 +1 될 것이고, dispatch({type: ‘DECREMENT’}) 를 호출하면 state 값이 -1 될 것이다.

function counter(state = 0, action) { switch (action.type) { case ‘INCREMENT’: return state + 1 case ‘DECREMENT’: return state – 1 default: return state } }

Subscribe

store 의 subscribe 메서드에 () => console.log(store.getState()) 의 함수( listner )를 넘겨주었다. 해당 함수는 앞으로 store 의 dispatch 가 호출될 때마다 콘솔에 변경된 state 의 값을 출력할 것이다.

store.subscribe(() => console.log(store.getState())))

따라서 아래와 같이 dispatch 함수를 호출하면 state 값이 초기값 0 에서 +1 되고, 해당 값은 콘솔에 출력된다.

store.dispatch({ type: ‘INCREMENT’ })

참고

예제를 통해 리덕스(redux)를 연습해봅시다.

먼저 다운로드 해야할 것들이 있습니다.

저번 시간에 만든 버튼 앱에 리덕스를 적용시키려면 우선 다운 받아야할 것들이 있습니다.

yarn add redux react-redux

해당 명령어를 콘솔에서 실행시켜주세요. redux와 react-redux를 다운받을 수 있습니다.

해당 모듈들을 다운로드 했다면 이제 리덕스 폴더를 만들어보도록 하겠습니다.

src/reducers/index.js 파일을 만들어주세요.

예제에서는 리듀서를 하나로 사용하지만 프로젝트가 커지면 여러개의 리듀서를 사용하고 하나로 통합하는 경우도 있습니다. 예제는 간단한 것이 좋으므로 reducers 폴더 안에 index에 모든 것을 다 정의해보도록 하겠습니다.

액션 만들기

먼저 정의해야할 것은 액션입니다. 액션은 어떤 행동을 할 지 정의해주는 것이라고 생각하시면 됩니다. 우리는 버튼을 누르면 증가하는 행동을 원하기 때문에 INCREMENT라는 액션을 정의해주면 됩니다.

//액션 정의하기 cosnt INCREMENT = “INCREMENT”;

그리고는 액션 생성 함수를 만들어주시면 됩니다. 액션은 객체로 전달되어야 합니다. 그래서 좀 더 편하게 객체를 만들어주기 위해 정의한 액션을 이용해서 액션 생성 함수를 만들어주는 것입니다.

액션 생성 함수는 객체를 리턴합니다. 이때 type은 필수 키입니다. 타입에 우리가 정의한 액션을 넣어주시면 됩니다.

리듀서 만들기

리덕스는 상태(state)를 컴포넌트 밖에 꺼내놓고 사용하는 것이라고 했습니다. 좀 더 세분화해서 표현하면 전역적으로 있는 상태를 “스토어”라고 합니다. 그리고 그 스토어는 “리듀서”라는 함수를 통해서만 변경될 수 있습니다.

리듀서는 2개의 매개변수를 가집니다. 바로 state와 action입니다. 이전 상태에 액션에 따라 새로운 상태를 리턴하는 것이 리듀서의 역할입니다. 그래서 보기 좋게 표현하기 위해서 내부에 switch 문을 통해서 정의합니다. if – else if – else 구문과 같습니다. switch 옆에 있는 값에 따라서 명령을 실행합니다. initialState는 state의 값이 undefined, 즉 맨 처음 상태일 때 값을 알려주는 것입니다. 우리 컴포넌트 내부의 숫자는 0부터 시작하니 값을 거기에 맞게 전달했습니다.

export default reducer;

이제 리듀서를 내보내면 됩니다. index 파일에서 리듀서 말고 또 하나 내보낸 것이 있습니다. 바로 액션 생성 함수 입니다. 액션을 리듀서에 전달하는 것을 “디스패치”라고 하는데 디스패치할 때에 사용하기 위해 액션 생성 함수도 내보낸 것입니다. 잊지말아 주세요. 버튼을 누르면 숫자가 하나 증가하는 것(버튼을 누르면 액션이 만들어져서 리듀서에 전달됩니다.)을 구현하기 위함입니다.

스토어 만들고 앱과 리덕스 연결하기

리듀서를 만들었으니 이제 스토어를 생성하면 됩니다.

코드를 하나씩 살펴볼까요? 프로젝트의 인덱스 파일에 우선 우리가 만든 리듀서를 갖고옵니다. 그리고 다운로드한 리덕스 모듈에서 createStore 함수를 통해서 스토어를 만들고, 리듀서를 전달하면 됩니다. 스토어를 만드는 방법은 아주 간단하죠?

리덕스는 리액트만 이용하는 것이 아닙니다. 아주 다양한 곳에서 활용되는 기술이죠. 그래서 리액트 프로젝트에 연결하려면 react-redux 모듈처럼 연결을 도와주는 모듈이 필요합니다. 해당 모듈에서 Provider를 갖고와서 가장 상위 컴포넌트인 App을 감싸주고 store를 전달해주면 리덕스와의 연결을 완료한 것입니다. 아주 쉽죠?

하위 컴포넌트에서 상태 값 가져오기

연결했으니 이제 하위 컴포넌트에서 값을 가져오면 됩니다.

일단 하위 컴포넌트의 파일 구조를 약간 바꿔볼까요?

저는 components라는 폴더 밑에 Nav와 Button이라는 폴더를 만들고 그 안에 각각 Nav.js와 index.js, Button.js와 index.js 파일을 만들었습니다.

Button/ Button.js index.js Nav/ Nav.js index.js

위와 같은 형태입니다. Button.js나 Nav.js에는 이전 포스팅에서 사용했던 코드 그대로 사용하시면 되고, index.js를 만든 이유는 이 파일 안에서 리덕스 값을 받아오기 위해서이고, 또 하나는 App.js 등 부모 컴포넌트에서 불러올 때 import Button from ‘./components/Button/Button’이 아니라 from ‘./components/Button’으로 불러오기 위해서입니다.

파일을 찾을 때 우선 index.js를 찾기 때문에 폴더까지만 위치를 설정해두어도 폴더/index 파일을 찾기 때문에 가능합니다.

인덱스 파일 안에서는 무슨 일을 해야할까요? 우선 버튼 부터 살펴보겠습니다.

(전역적으로 있는)상태 값을 컴포넌트의 prop로 갖고 오는 것을 정의하는 함수는 mapStateToProps이고, 액션을 리듀서에 전달하는 디스패치를 컴포넌트의 props에 갖고 오는 것을 정의하는 함수를 mapDispatchToProps라고 합니다. 이 중에서 필요한 것이 있다면 인덱스에서 정의하고, 해당 하위컴포넌트에 연결시켜서 내보내야 합니다.

버튼의 경우엔 number라는 state의 값도 받아야 하고, 클릭하면 또 숫자가 증가해야 한다는 액션도 보내야하니 둘다 필요합니다. 그래서 두 개를 다 정의해주도록 하겠습니다.

이제 이 두 함수를 컴포넌트에 연결시켜보겠습니다.

react-redux에서 connect 함수를 갖고와서 정의한 함수를 전달하고 리턴값에 다시 컴포넌트를 전달해서 내보내면 됩니다.

부모 컴포넌트(App)에서 전달하는 것이 아무것도 없는데도 똑같이 실행되고 있는 것을 확인할 수 있습니다.

좀 길었지만 리덕스에 대해서 약간은 이해가 되셨나요?

공감은 제작자에게 큰 힘이 됩니다.

키워드에 대한 정보 리액트 리덕스 예제

다음은 Bing에서 리액트 리덕스 예제 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 React 입문자들이 알아야할 Redux 쉽게설명 (8분컷)

  • 리덕스
  • redux
  • 리덕스강의
  • redux install
  • 리덕스 설치
  • 리덕스 특징
  • 리듀서
  • reducer
  • 액션
  • vuex

React #입문자들이 #알아야할 #Redux #쉽게설명 #(8분컷)


YouTube에서 리액트 리덕스 예제 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 React 입문자들이 알아야할 Redux 쉽게설명 (8분컷) | 리액트 리덕스 예제, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  워싱턴 뉴스 투데이 | 082922 Wktv 워싱턴 뉴스투데이 상위 47개 베스트 답변

Leave a Reply

Your email address will not be published. Required fields are marked *