[ Redux Toolkit(Feat. Flux Pattern) ]
▶ 리덕스툴킷
리덕스툴킷
리덕스 툴킷은 줄여서 RTK라고 하고 리덕스를 개량한 것으로 생각하면 됨
리덕스를 사용하기 위해 작성했던 ducks 패턴의 요소들이 전체적인 코드의 양을 늘린다는 개발자들의 불만이 발생하기 시작했고 리덕스 팀에서는 이것을 수용하여 코드는 더 적고 리덕스를 더 편하게 쓰기 위한 기능들을 흡수해서 만든 것
리덕스 툴킷은 리덕스와 구조나 패러다임이 모두 똑같음 즉 새로운 것이 아님
리덕스의 전체 코드의 양을 줄이기 위해 새로운 API가 추가되었고 ducks패턴의 요소들이 어느정도 자동화 됨
컴포넌트에서 useSelector를 통해서 사용하는 것은 모두 똑같음 바뀐 부분은 모듈 파일 뿐
▶ 일반 리덕스와 코드 비교
툴킷 설치하기
yarn add react-redux @reduxjs/toolkit
count 프로그램 코드 비교
Action Value, Action Creator를 별도로 생성하고 리듀서에서 값을 어떻게 변화시킬 지 만들줘야 함
// 일반 리덕스 예시 코드
// Action Value
const ADD_NUMBER = "ADD_NUMBER";
const MINUS_NUMBER = "MINUS_NUMBER";
// Action Creator
export const addNumber = (payload) => {
return {
type: ADD_NUMBER,
payload,
};
};
export const minusNumber = (payload) => {
return {
type: MINUS_NUMBER,
payload,
};
};
// Initial State
const initialState = {
number: 0,
};
// Reducer
const counter = (state = initialState, action) => {
switch (action.type) {
case ADD_NUMBER:
return {
number: state.number + action.payload,
};
// [퀴즈 답]
case MINUS_NUMBER:
return {
number: state.number - action.payload,
};
default:
return state;
}
};
// export default reducer
export default counter;
// 리덕스 툴킷 예시코드
// src/redux/modules/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
number: 0,
};
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
addNumber: (state, action) => {
state.number = state.number + action.payload;
},
minusNumber: (state, action) => {
state.number = state.number - action.payload;
},
},
});
// 액션크리에이터는 컴포넌트에서 사용하기 위해 export 하고
export const { addNumber, minusNumber } = counterSlice.actions;
// reducer 는 configStore에 등록하기 위해 export default함
export default counterSlice.reducer;
리덕스 툴킷을 사용해서 만든 counter 프로그램 모듈 일반 리덕스를 사용했을때 보다 코드의 양이 줄었음
차이점은 Action Value와 Action Creator를 직접 생성해주지 않고 Action Value, Action Creator, Reducer가 하나로 합쳐짐 Slice라는 API를 사용함 이 슬라이스를 사용하면 3개를 각각 만들어줄 필요 없이 한번에 3개가 모두 만들어짐
슬라이스는 createSlice라는 API를 통해 만들 수 있음
그리고 그 인자로 설정정보를 객체로 받는데 그 안에 필수로 작성해줘야 하는 값은 name, initialState, reducers가 있음
//createSlice API 뼈대
const counterSlice = createSlice({
name: '', // 이 모듈의 이름
initialState : {}, // 이 모듈의 초기상태 값
reducers : {}, // 이 모듈의 Reducer 로직
})
counterSlice 리듀서 객체 안에서 만들어주는 함수가 리듀서의 로직이 되면서도 동시에 Action Creator가 된다는 점
Action Value까지 함수의 이름을 따서 자동으로 만들어짐 그래서 Reducer만 만들어주면 됨
// counterSlice.js의 Slice 구조
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
// 리듀서 안에서 만든 함수 자체가 리듀서의 로직이자, 액션크리에이터가 됨
addNumber: (state, action) => {
state.number = state.number + action.payload;
},
minusNumber: (state, action) => {
state.number = state.number - action.payload;
},
},
});
일반 리덕스에서 export를 통해서 각각의 Action Creator를 내보내주었던 것을 아래 코드를 작성하면 똑같이 내보낼 수 있음 그래서 리듀서에 로직을 추가할 때마다 함수를 추가해서 내보내주면 됨
// 액션크리에이터는 컴포넌트에서 사용하기 위해 export 하고
export const { addNumber, minusNumber } = counterSlice.actions;
// reducer 는 configStore에 등록하기 위해 export default 함
export default counterSlice.reducer;
ConfigStore 비교
// 일반 리덕스 combineReducers 예시 코드
import { createStore } from "redux";
import { combineReducers } from "redux";
import counter from "../modules/counter";
const rootReducer = combineReducers({
counter,
});
const store = createStore(rootReducer);
export default store;
configStore에서도 아래와 같이 작성하면 되며 크게 달라지는 점은 없음
// 리덕스 툴킷
import { configureStore } from "@reduxjs/toolkit";
import counter from "../modules/counterSlice";
import todos from "../modules/todosSlice";
/*
* 모듈(Slice)이 여러개인 경우
* 추가할때마다 reducer 안에 각 모듈의 slice.reducer를 추가해줘야 함
*/
const store = configureStore({
reducer: { counter: counter, todos: todos },
});
export default store;
▶ Redux Devtools 사용하기
devtools
리덕스를 사용하면 리덕스 devtools를 사용할 수 있음 다른 패키지에서 찾아볼 수 없는 굉장히 강력한 개발툴
현재 프로젝트의 state 상태라던가 어떤 액선이 일어났을 때 그 액션이 무엇이고 그것으로 인해 어떤 state가 어떻게 변경되었는지 등 리덕스를 사용하여 개발할 때 아주 편리하게 사용할 수 있음
사용하기 위해서는 구글 웹스토어에서 플러그인을 설치하면 됨
사용하는 법
- 웹스토어에서 devtools를 설치하고 리액트 프로젝트에서 리덕스를 사용하고 있으면 플러그인에 녹색 불이 켜짐
- 개발자도구 탭에서 Redux라는 메뉴를 볼 수 있음
- 여러가지 기능을 실행해보면 devtools에서 확인 할 수 있음
프로젝트가 점점 복잡해질수록 로그를 확인하는 것이 쉽지 않은데 이 툴을 이용해서 정말 쉽게 디버깅을 할 수 있음
툴킷이 아닌 일반 리덕스에서 devtools를 사용하고자 한다면 별도 설정이 필요함
툴킷은 devtools이 내장되어 있기 때문에 별도의 코드 설정 없이 바로 사용 가능함
▶ Flux 패턴
Flux
Flux는 애플리케이션에서 데이터를 취급하기 위한 패턴(pattern)임
Flux와 React는 Facebook이 가지고 있었던 특정한 문제점들을 해결하기 위해서 개발되었음
Facebook 문제점
Facebook은 여러 문제점이 있었고 이것을 해결하기 위해 근본적인 문제점을 찾았음
Facebook이 찾은 문제점은 양방향 데이터 바인딩
MVC패턴에서 컨트롤러는 모델의 데이터를 조회하거나 업데이트하는 역할을 하며 모델의 변화는 뷰의 반영함
사용자는 뷰를 통해 데이터를 입력하는데 사용자의 입력은 모델에 영향을 주기도 함

문제는 페이스북과 같은 대규모 애플리케이션에서는 MVC가 너무 빠르게 너무 복잡해진다는 것
페이스북 개발팀에 따르면 구조가 너무 복잡해진 탓에 새 기능을 추가할 때마다 크고 작은 문제가 생겼으며 코드의 예측이나 테스트가 워려워지고 새로운 개발자가 오면 적응하는데만 한참이 걸려 빠르게 개발할 수가 없었음
즉 소프트웨어 품질을 담보하기가 힘들어진것
예시로 페이스북의 안 읽은 글 갯수 표시가 있는데 사용자가 읽지 않았던 글을 읽으면 읽지 않은 글 갯수에서 읽은 글 수 만큼 빼면 되는 단순해보이는 기능인데도 이를 MVC로 구현하기 어려웠던 것
어떤 글을 '읽음' 상태로 해두면 먼저 글을 다루는 thread 모델을 업데이트 해야하고 동시에 unread count 모델도 업데이트 해야함 대규모 MVC 애플리케이션에서 이 같은 의존성과 순차적 업데이트는 종종 데이터 흐름을 꼬이게 하여 예기치 못한 결과를 일으킴
해결책: 단방향 데이터 흐름(unidirectional data flow)
Facebook은 다른 종류의 아키텍처를 시도하기로 결정함
Flux 애플리케이션은 크게 세 부분으로 구성되는데 디스패쳐, 스토어, 뷰
다만 여기서 말하는 뷰는 MVC 뷰와 달리 스토어에서 데이터를 가져오는 한편 데이터를 자식 뷰로 전달하기도 하는 일종의 뷰-컨트롤러로 보아야 함 Flux 아키텍처의 가장 큰 특징으로는 단방향 데이터 흐름을 들 수 있음
데이터의 흐름은 언제나 디스패쳐에서 스토어로 스토어에서 뷰로 뷰에서 액션으로 다시 액션에시 디스패쳐로 흐름

Flux 동작
- 액션생성자(the action creator)
모든 변경사항과 사용자와의 상호작용이 거쳐가야 하는 액션의 생성을 담당
언제든 애플리케이션의 상태를 변경하거나 뷰를 업데이트하고 싶다면 액션을 생성해야만 함
액선 생성자는 타입과 페이로드를 포함한 액션을 생성함
- 디스패쳐(dispatcher)
액션 생성자가 액션 메세지를 생성한 뒤에는 디스패쳐로 넘겨줌 디스패쳐는 액션을 보낼 필요가 있는 모든 스토어(store)를 가지고 있고 액션 생성자로부터 액션이 넘어오면 여러 스토어에 액션을 보냄
처리는 동기적으로(synchronously) 실행됨
Flux는 다른 디스패쳐는 다른 아키텍처들과는 조금 다르게 스토어가 특정 액션만 구독(subscribe)하지 않고 모든 액션을 일단 받은 뒤 처리할지 말지를 결정
- 스토어(store)
스토어는 애플리케이션 내의 모든 상태와 그와 관련된 로직을 가지고 있음
모든 상태 변경은 반드시 스토어에 의해서 결정되어야만 하며 상태 변경을 위한 요청을 스토어에 직접 보낼 순 없음
스토어에는 설정자(setter)가 존재하지 않으므로 상태 변경을 요청하기 위해서는 반드시 모든 정해진 절차를 따라야만 함
즉 무조건 액션 생성자/디스패쳐 파이프라인을 거쳐서 액션을 보내야만 함
- 컨트롤러 뷰(the controller view)와 뷰(the view)
뷰는 상태를 상태를 가져오고 유저에게 보여주고 입력받을 화면을 렌더링하는 역할을 맡음
뷰는 내부에 대해서 아는것은 없지만 받은 데이터를 처리해 사람들이 이해할 수 있는 포맷(HTML)으로 바꾸고
컨트롤러 뷰는 스토어와 뷰 사이의 중간관리자 역할을 함
상태가 변경되었을 때 스토어가 그 사실을 컨트롤러 뷰에게 알려주면 컨트롤러 뷰는 자신의 아래에 있는 모든 뷰에게 새로운 상태를 넘겨줌
● 준비
먼저 애플리케이션이 초기화할 때 딱 한번 준비과정을 가짐
- 스토어는 디스패쳐에 액선이 들어오면 알려달라고 말해둠
- 컨트롤러 뷰는 스토에게 최신 상태를 물음
- 스토어가 컨트롤러 뷰에게 상태를 주면 렌더링하기 위해 모든 자식 뷰에게 상태를 넘겨줌
- 컨트롤러 뷰는 스토어에게 상태가 바뀔 때 알려달라고 다시 부탁함
● 데이터 흐름
준비과정이 끝나면 애플리케이션은 유저 입력을 위한 준비가 완료됨
사용자의 입력으로 인한 액션을 생겼을 경우 사용자 입력으로부터 데이터 흐름을 만들것
- 뷰는 액션 생성자에게 액션을 준비하라고 말함
- 뷰는 액션 생성자에게 액션을 준비하라고 말함
- 액션 생성자는 액션을 포맷에 맞게 만들어 디스패쳐에 넘겨줌
- 디스패쳐는 들어온 액션에 순서에 따라 알맞는 스토어로 보냄
- 각 스토어는 모든 액션을 받게 되지만 필요한 액션만을 골라서 상태를 필요에 맞게 변경
- 상태 변경이 완료되면 스토어는 자신을 구독하고 있는 컨트롤러 뷰에게 그 사실을 알림
- 연락을 받은 컨트롤러 뷰들은 스토어에게 변경된 상태를 요청함
- 스토어가 새로운 상태를 넘겨주면 컨트롤러 뷰는 자신 아래의 모든 뷰에게 새로운 상태에 맞게 렌더링하라고 알림
[ json-server ]
▶ json-server
json-server 정의 및 사용하는 이유
json-server란 아주 간단한 DB와 API 서버를 생성해주는 패키지
사용하는 이유는 Backend(이하 BE)에서 실제 DB와 API Server가 구축할 때까지 Frontend(이하 FE) 개발에 임시적으로 사용할 mock data를 생성하기 위함 json-server를 통해서 FE에서는 BE가 하고 있는 작업을 기다리지 않고 FE의 로직과 화면을 구현 할 수 있어 효율적으로 협업을 할 수 있음
json-server 설치하기
터미널에서 패키지 설치
yarn add json-server
▶ json-server 사용하기
json-server 실행하기
json-server가 간단한 패키지이긴 하나 말 그대로 서버임 그래서 리액트와는 별개로 따로 실행해 주어야 함
즉 리액트도 start하고 json-server도 start 해야 함 그래야 리액트와 json-server가 서로 통신할 수 있음
yarn json-server --watch db.json --port 3001
명령을 통해 json-sever를 실행함 명령어의 대략적인 뜻은 db.json 이라는 것을 db로 삼고 3001 포트에서 서버를 시작하겠다는 뜻 이렇게 명령어를 입력하면 db.json이 자동으로 생성됨 이 json 파일을 db로 사용하는 것

서버가 정상적으로 켜지면 이런 이미지가 보이게 됨
db.json 수정하고 브라우저에서 확인하기
db.json이 생성되면서 기본값을 넣어준는데 지우고 자신이 하고 싶은데로 사용하면 됨
{
"todos": [
{
"id": 1,
"title": "json-server",
"content": "json-server를 배워봅시다."
}
]
}
만든 API 서버가 잘 작동하고 있는지 브라우저에서 확인하려면 http://localhost:3001/todos로 확인하면 됨
브라우저 주소에 URL을 입력한다는 것은 GET요청 즉 만든 API 서버에 GET 요청을 한 셈

서버의 터미널에서는 GET요청을 했다고 알려줌
[ HTTP ]
▶ 통신
개념
통신을 영어로 하면 'communication'
웹 프로그래밍 세계에도 서로 대화가 필요함 이를 웹 통신이라고 함
이 대화방법은 보통 ‘데이터’로 이루어짐 즉 서버(웹 서버)와 클라이언트(웹 브라우저)가 데이터로 대화를 나누는 것
▶ 웹 통신은 약속(=프로토콜)
프로토콜
서버(웹 서버)와 클라이언트(웹 브라우저)가 대화하기 위해 서로 약속된 방식이 필요함
방식대로 서로 데이터를 주고 받아야 오류가 없음 이런 약속을 프로토콜(protocol)이라고 함
특히 웹에서 서버와 클라이언트간 주고 받은 상호간의 약속(프로토콜)을 HTTP 프로토콜이라고 함
웹에서는 브라우저와 서버가 데이터를 주고 받기 위해 HTTP 프로토콜을 사용하고 있음
요청(Request)과 응답(Response)

스파르타 코딩클럽
서버와 클라이언트가 서로 데이터를 주고 받기(대화하기) 위해서는 항상 ‘요청(request)’을 해야 하고 그에 따른 ‘응답(response)’을 줌 보통 클라이언트가 대화를 시도하고 서버는 요청을 받아 그에 따른 응답을 주는 쪽을 의미함
URL에 대해서
URL구조는
- protocol
- domain(sub domain, domain name)
- resource path(path/page)
- query variable, path variable

[출처 : https://www.hostinger.in/tutorials/what-is-a-url ]
메서드
- GET: 조회
- POST: 생성
- PUT, PATCH: 수정(변경)
- DELETE: 삭제
더 많음
HTTP request methods - HTTP | MDN
HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. Although they can also be nouns, these request methods are sometimes referred to as HTTP verbs. Each of them implements a different semantic, but som
developer.mozilla.org
상태코드
클라이언트가 서버에 어떤 요청(request)를 하고 나면 서버는 그에 맞는 응답(response)를 제공함
그 때 각 응답은 상태코드를 갖음
- 1xx(정보) : 요청을 받았으며 프로세스를 계속 진행함
- 2xx(성공) : 요청을 성공적으로 받았으며 인식했고 수용함
- 3xx(리다이렉션) : 요청 완료를 위해 추가 작업 조치가 필요함
- 4xx(클라이언트 오류) : 요청의 문법이 잘못되었거나 요청을 처리할 수 없음
- 5xx(서버 오류) : 서버가 명백히 유효한 요청에 대한 충족을 실패
'항해99' 카테고리의 다른 글
리액트 심화주차3 (1) | 2023.07.05 |
---|---|
리액트 심화주차2 (0) | 2023.07.04 |
리액트 숙련주차4 (0) | 2023.06.28 |
리액트 숙련주차 3 (0) | 2023.06.27 |
리액트 숙련주차 2 (1) | 2023.06.27 |
댓글