분류 Reactjs

Redux (및 React-Redux)에 대한 유일한 소개

컨텐츠 정보

  • 조회 351 (작성일 )

본문

이 글은 Redux와 React Redux의 기본 개념을 이론과 예제를 통해 가능한 한 간단하고 명확하게 설명합니다.


Redux 단독과 React-Redux (React에서 Redux 구현)의 두 부분으로 나뉩니다.


https://medium.com/javascript-in-plain-english/the-only-introduction-to-redux-and-react-redux-youll-ever-need-8ce5da9e53c6 


  1. 첫 번째 부분에서는 Redux의 Actions, Reducers 및 Store를 살펴 보겠습니다.
    그런 다음 간단한 바닐라 JavaScript 애플리케이션에서 Redux를 구현할 것입니다.
    마지막으로 애플리케이션 상태를 초기화하고 애플리케이션을 Redux DevTools 브라우저 확장으로 연결하는 방법에 대해 설명합니다.
  2. 두 번째 부분에서는 React에서 동일한 Redux 응용 프로그램을 구현하고 React 구성 요소에서 Redux와 연결할 수 있는 패키지인 React-Redux에 대해 알아 봅니다.

GitHub는 두 프로젝트 모두에 연결됩니다.

노트 :

  • 두 부분에서 JavaScript와 EcmaScript 6/7에 대해 잘 알고 있다고 가정합니다.
  • 첫 번째 부분에서는 이전에 NodeJS로 작업했으며 컴퓨터에 NodeJS 및 NPM이 설치되어 있고 Webpack 및 Babel이 무엇인지 알고 있다고 가정합니다.
  • 이 기사에서는 NPM을 사용하려고 합니다. yarn을 사용하는 경우 Redux 및 React-Redux 설명서의 설치 페이지를 참조하십시오.
  • 두 번째 부분에서는 React에서 ToDo 애플리케이션보다 더 복잡한 애플리케이션을 작성하는 것이 편하다고 가정하고 HOC (Higher Order Components)가 무엇인지 알고 있습니다.
  • 모든 것을 가능한 한 단순하게 유지하기 위해 스타일을 작성하지 않습니다. 아무 이유 없이 누군가가 한 번에 불필요한 물건을 한 번에 던져서 혼란스럽게 할 때의 상황을 알고 있습니다.
  • Redux 브라우저 확장 프로그램을 사용하지 않습니다. 이 기사의 첫 부분 끝 부분에서 Redux DevTools 확장에 대해 간략히 살펴 보겠지만 거의 모든 프로젝트에서 사용할 가능성이 높으므로 더 익숙해 지도록 강력히 권장합니다. 
  • Redux를 Flux와 같은 유사한 라이브러리와 비교하지는 않겠습니다. 그러한 주제에 관심이 있다면 스스로 연구 해보십시오.
  • 이 기사를 읽은 후에는 Redux와 React-Redux의 문서를 살펴 보는 것이 좋습니다.이 기사의 모든 내용을 다루지는 못하기 때문입니다.

또한, 나는 이것이 또 다른 ToDo 튜토리얼이 되기를 원하지 않습니다 (ToDo 튜토리얼 자체가 아파요, Hello World v2.0과 비슷합니다). 그래서 우리는 사용자가 대신 노트를 작성할 수 있는 응용 프로그램을 만들 것입니다. 

각 메모의 제목과 내용을 지정할 수 있습니다.


더 이상 고민하지 않고 학습을 시작합시다!


1 부 — Redux 


Redux는 애플리케이션의 상태를 관리하는 데 널리 사용되는 JavaScript 라이브러리입니다. 매우 일반적이며 React와 함께 일할 경우 이미 그 소식을 들었을 가능성이 있습니다.


응용 프로그램 상태가 무엇인지 모르는 사용자에게는 응용 프로그램의 후반에 다양한 목적으로 사용하는 정보를 보유하는 전역 객체와 같습니다 (예 : 렌더링 할 구성 요소 및 시기에 대한 결정, 저장된 데이터 렌더링 등). ).


우리가 자주 직면하는 예는 페이지가 로드 되는 동안 로드 표시기를 표시하는 것입니다. 이 경우 해당 용도로만 스토어를 사용한 경우 상태 객체는 페이지 로드 여부에 관계없이 부울 필드를 저장하고 해당 필드를 사용하여 로드 표시기 표시를 전환합니다.


또 다른 예는 — 소셜 미디어 응용 프로그램을 구축하는 경우 응용 프로그램 상태 (현재 사용자 정보, 뉴스 피드에 렌더링 할 현재 게시물, 사용자 프로필의 현재 스토리)에 여러 개체와 배열을 저장하는 것입니다. 다음과 같습니다.


Redux에 어떤 데이터를 보관해야 하는 지에 대한 규칙은 없으므로 모든 것이 귀하에게 달려 있습니다. 그러나 항상 직렬화 가능한 데이터만 저장해야 합니다.


큰 응용 프로그램은 응용 프로그램 상태가 커서 응용 프로그램이 커질수록 관리하기가 점점 더 불편 해집니다. 그렇기 때문에 Redux와 같은 상태 관리 라이브러리가 필요합니다.


Redux의 작동 방식은 매혹적이고 간단합니다. 패턴은 매우 직관적이며 함수 이름은 자명합니다. 날 믿어, 당신은 그것을 사랑합니다!


Redux를 시작하기 전에 Redux가 따르는 두 가지 중요한 패턴에 대해 언급하고 싶습니다 (Redux 응용 프로그램을 작성하는 동안 항상 이 정보를 항상 기억해 두는 것이 좋습니다).


Redux가 따르는 하나의 패턴은 “Single Source Of Truth”라고 하며, 이는 전체 애플리케이션의 유일한 상태를 저장하는 유일한 장소 (Store라고 함)를 가지고 있음을 의미합니다. 다시 말해, 하나의 앱, 하나의 스토어, 하나의 상태가 있습니다.


그러나 React 또는 다른 프레임 워크의 구성 요소는 자체 내부 상태도 자유롭게 포함 할 수 있습니다. 일반적으로 문자 그대로 모든 것을 응용 프로그램 상태에 두기를 원하지 않습니다.


Redux가 따르는 또 다른 패턴을 "불변성"이라고 합니다. 그리고 이 용어는 다른 프레임 워크와 라이브러리에서도 자주 발견됩니다.


즉, 불변성은 상태 객체와 해당 속성을 직접 변경하지 않음을 의미합니다. 대신 새 객체를 만들고 새 응용 프로그램 상태를 다시 계산하여 새로 만든 객체로 업데이트합니다. 우리는 이전 상태 객체를 그대로 두기를 원합니다.


Redux의 세 가지 빌딩 블록 


1*Xr2pZxU0OqIO4cABIXml8g.png 




Redux의 3 가지 빌딩 블록 — 액션, 리듀서 및 스토어



Redux에는 3 가지 주요 부분이 있습니다.

  1. Actions
  2. Reducers
  3. Store

Store 

이미 짐작 했듯이 store는 애플리케이션의 상태를 유지합니다. store는 실제로 클래스가 아닌 객체이지만 처음에는 하나의 느낌이 들 수 있습니다. 여기에는 함수 및 기타 객체와 같이 애플리케이션의 상태 외에 몇 가지 추가 사항이 포함됩니다.


이론적으로 여러 저장소를 생성 할 수 있지만 이는 Redux가 따르는 패턴에 위배됩니다. 애플리케이션 당 하나의 store만 작성합니다.


store가 업데이트 될 때마다 이벤트를 청취하도록 구독할 수 있습니다. 비 React 앱에서는 이 구독을 사용하여 UI를 업데이트 할 수 있습니다 (예 : 애플리케이션에서 수행 할 때).


Redux의 상태는 JavaScript 객체의 형태이며 "상태 트리"라고도 합니다. 저장하려는 값을 입력 할 수 있으며 필요한 만큼 중첩 할 수 있습니다.


Actions 


액션은 무슨 일이 있었는지 설명하지만 앱 상태 변경 방법을 설명하지 않는 일반 JavaScript 객체입니다.


애플리케이션 상태를 업데이트하려고 할 때마다 스토어 인스턴스로 파견 (보내기)합니다. 나머지는 reducers로 처리되며 잠시 후에 익숙해 질 것입니다.


기억해야 할 중요한 사항 중 하나는 Redux에 작업 객체에 유형 필드가 포함되어야 한다는 것입니다. 이 필드는 어떤 종류의 작업을 전달하는지 설명하는 데 사용되며 일반적으로 파일에서 내보내는 상수여야 합니다.

action 오브젝트의 다른 모든 필드는 선택 사항이며 사용자에게 달려 있습니다.


예를 들어, 구축 할 앱에서 사용자가 '메모 추가'버튼을 클릭 할 때마다 다음 조치와 유사한 것을 상점으로 발송합니다.


{ type: ADD_NOTE, title: 'Some Title', content: 'This is an action object' } 


store 변경 방법에 대한 논리는 다루지 않습니다. 제공된 제목과 내용이 포함 된 새 메모를 추가하고 싶다는 정보만 제공합니다. 제목 및 내용 필드는 선택 사항입니다. 우리가 말했듯이 type 필드는 필수입니다.


자주 발생하는 또 다른 용어는 Action Creators입니다. 기본적으로 일반 JavaScript 객체를 생성하고 반환하는 함수입니다. 그것들은 액션에 동적 데이터를“삽입”하거나 동적 데이터를 사용하여 액션을 생성 할 수 있도록 사용됩니다. 우리의 경우에는 제목과 내용이라는 두 가지 매개 변수를 받는 함수가 있고 제공된 정보와 함께 일반 JavaScript 객체를 반환합니다.


function addNote(title, content) {
return { type: ADD_NOTE, title: title, content: content };
}


Reducers 


Reducers는 앱 상태 변경 방법을 정의하는 순수한 함수입니다. 즉, 새로운 응용 프로그램 상태 또는 적어도 일부를 재 계산하는 데 사용됩니다.


store에 action를 발송(dispatch)할 때마다 조치(action)가 감속기(reducer)로 전달됩니다.

reducer 함수는 두 개의 인수, 즉 이전 앱 상태, 작업이 전달되고 새 앱 상태를 반환합니다.


(previousState, action) => newState 


다시 말해 리듀서는 전달한 액션 (및 해당 유형)을 기반으로 앱의 새로운 상태를 계산합니다.


실제 응용 프로그램에서는 리듀서가 매우 복잡해집니다. 리듀서 복잡성을 처리하기 위해 여러 개의 간단한 리듀서로 청크 한 다음 나중에 combineReducers라는 Redux 도우미 함수와 결합합니다.


메인 reducer는 일반적으로 루트 감속기(Root Reducer)라고 합니다.


데이터 흐름 


처음에는 약간 복잡해 보이지만 Redux의 데이터 흐름은 실제로 매우 간단합니다.


1*jVw1kwKpvWsKcqp9o29iHA.png 

사용자가 이벤트를 트리거하고 (예 : '메모 추가'버튼 클릭) 앱 상태가 업데이트 됩니다 (즉, 새로운 메모가 앱 상태에 삽입 됨). 후드 아래에서 일어나는 일은 다음과 같습니다.

  1. 버튼 클릭 핸들러 함수는 store.dispatch() 메소드를 사용하여 상점에 조치를 발송합니다.
  2. Redux는 디스패치된 조치(action)를 감속기(reducer)로 전달합니다.
  3. 상점(store)은 리듀서가 리턴 한 새 상태를 저장합니다.
  4. 우리가 상점에 가입했기 때문에 우리가 제공한 함수가 호출되고 그에 따라 UI가 업데이트 됩니다 (즉, 메모 목록에 새 메모 추가)

앱 설정 


이제 첫 번째 응용 프로그램 만들기를 시작하겠습니다.

  • Linux를 사용하는 경우 프로젝트 디렉토리로 이동하여 터미널에 붙여 넣으십시오. 필요한 모든 파일과 폴더를 직접 작성해야 하는 번거로움을 덜어줍니다.

mkdir -p redux-notes-app/{dist,src/{actions,reducers,store}} && cd redux-notes-app && touch {index.html,.babelrc,webpack.config.js,src/{actions/actions.js,reducers/reducers.js,store/store.js,main.js}} 


  • Linux를 사용하지 않는 경우 필요한 파일과 폴더를 수동으로 작성하고 폴더 구조가 내 구조와 동일한 지 확인하십시오.

1*9hkUQXNGLwYzO1KnBaS4Sw.png 


  • 새 프로젝트 디렉토리 내에서 다음 명령을 실행하십시오.
npm init -ynpm i reduxnpm i webpack webpack-cli @babel/core babel-loader @babel/preset-env --save-dev


  • webpack.config.js 파일 안에 다음 내용을 삽입하십시오
const path = require('path');
const config = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
module.exports = config;


.babelrc 파일 안에 다음 내용을 추가하십시오.


{
"presets": ["@babel/preset-env"]
}


package.json 파일에서 scripts 객체에 다음 줄을 추가하십시오.


"dev": "webpack --watch --mode=development" 


  • 마지막으로 실행

npm run dev 


그리고 사업에 착수합시다!


앱 상태 정의 


코드 작성을 시작하기 전에 항상 종이 한 장을 가져 와서 응용 프로그램의 모든 기능을 작성하고, 모든 것이 상호 연결되는 방식에 대한 계획을 세우고, 응용 프로그램 상태에서 필요한 작업을 수행하는 방법을 배우는 것이 좋습니다. 앱 상태는 끝과 같아야 합니다.


다시 말해, 코드 작성에 직접 뛰어 들지 말고 계획을 세우십시오!


“계획에 투자 할 때마다 10 분의 실행 시간이 절약됩니다. 이것은 준다 당신은 에너지에 1,000 %의 수익을 올릴 수 있습니다!”— Brian Tracy 


마지막으로 애플리케이션 상태가 다음과 같다고 가정 해 봅시다.


{
notes: [
{
title: 'Note 1 Title',
content: 'Note 1 Content'
},
{
title: 'Note 2 Title',
content: 'Note 2 Content'
},
...

{
title: 'Note N Title',
content: 'Note N Content'
}
]
}


노트 배열 내부의 각 객체는 단일 노트를 나타냅니다.


즉, 우리의 앱 상태는 하나의 속성으로 구성된 매우 간단한 객체입니다.이 객체는 객체 배열 (개별 노트)이 될 것입니다. API를 사용하지 않기 때문에 메모의 ID가 배열의 색인 인 것으로 가정하므로 최종 메모 형식에서 누락 된 ID 필드가 됩니다.


초기 코드 


응용 프로그램에 필요한 초기 코드를 준비했습니다. index.html 파일에 다음 코드를 삽입하십시오.


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux Notes</title>
</head>
<body>
<h1>Redux Notes App</h1>
<h3>Add a Note</h3>
<form id="add-note">
Title: <br />
<input type="text" name="title">
<br />
Content: <br />
<textarea name="content" cols="30" rows="5"></textarea>
<br />
<button type="submit">Add Note</button>
</form>
<hr />
<h3>All Notes</h3>
<ul id="notes">
<li>
<b>Title</b>
<button data-id="5">x</button>
<br />
<span>Note Content</span>
</li>
</ul>
<script src="./dist/bundle.js"></script>
</body>
</html>


이제 src/main.js 파일에 이 코드를 삽입하십시오 :


// ------ HTML references ------
let notesUList = document.getElementById('notes');
let addNoteForm = document.getElementById('add-note');
let addNoteTitle = addNoteForm['title'];
let addNoteContent = addNoteForm['content'];
// ------ Redux ------
function deleteNote(index) {
// console.log(index);
}
function renderNotes() {
setDeleteNoteButtonsEventListeners();
}
// ------ Event Listeners ------
addNoteForm.addEventListener('submit', (e) => {
e.preventDefault();
// console.log('Title:', addNoteTitle.value, 'Content:', addNoteContent.value);
});
function setDeleteNoteButtonsEventListeners() {
let buttons = document.querySelectorAll('ul#notes li button');
for(let button of buttons) {
button.addEventListener('click', () => {
deleteNote(button.dataset.id);
});
}
}
// ------ Render the initial Notes ------
renderNotes();


1*NWOmsT2_4MoRuUevioicqg.png 


보시다시피 제목과 내용 필드 만 있는 간단한 양식입니다.


이 양식은 새 메모를 추가하는 데 사용됩니다.


ul#notes는 모든 메모를 목록 항목으로 렌더링 하는 곳입니다. 노트의 모양에 대한 템플릿 역할을 하는 하나의 하드 코딩 된 목록 항목이 있습니다.이 항목은 코드에서 즉시 제거됩니다.


메모 제목 바로 오른쪽에 있는 버튼을 눌러 메모를 삭제할 수 있습니다. 버튼의 data-id 속성은 삭제할 메모의 ID (색인)를 얻는 데 도움이 되므로 삭제해야 할 메모에 대한 아이디어를 제공합니다.