React에서 컴포넌트를 생성하고 이벤트를 통해 다른 컴포넌트에 변화를 줄 수 있었다. 상태(state)와 속성(props)을 이용한 컴포넌트 단위 개발 아키텍처를 React에서 사용했다.
하지만 단점이 있다.
- 최상위 컴포넌트에 설정된 state를 최하위 컴포넌트에서 썼을 때, 그 중간에 있는 컴포넌트들도 상태 데이터를 가진다. (props를 계속해서 내려줘야 하기 때문)
- Lifting State Up, Props를 여러번 작성해야 한다.
- 데이터 흐름이 복잡해짐
- 컴포넌트 구조가 바뀐다면, 데이터 흐름을 완전히 바꿔야 할 수 있다.
가독성 측면에서도 안 좋고 유지보수 측면에서도 좋지 못했다.
이러한 단점때문에 Redux같은 상태 관리 라이브러리를 사용한다. Redux는 컴포넌트와 상태를 분리하는 패턴이다. Redux는 전역 상태 관리를 할 수 있는 저장소인 Store를 제공한다. 모든 컴포넌트들이 Store에 접근해서 state를 사용할 수 있기 때문에 전보다는 깔끔한 데이터 흐름을 볼 수 있다.
MVC(Model-View-Controller). 소프트웨어 개발에서 사용되는 소프트웨어 아키텍처 패턴이다. MVC 패턴은 애플리케이션을 세 가지 주요 구성 요소로 분리하여 개발하는 방법을 제공한다.
Model은 애플리케이션의 데이터와 비즈니스 로직을 담당한다.
데이터베이스에서 데이터를 가져오거나 업데이트하고, 데이터를 조작하거나 가공하는 등의 작업을 수행한다.
Model은 일반적으로 애플리케이션의 상태를 표현하고 관리하는 역할을 한다.
View는 사용자 인터페이스(UI)를 말한다. 사용자에게 데이터를 시각적으로 표현하고, 사용자의 입력을 받아 컨트롤러에 전달한다. View는 모델의 상태를 보여주는 역할을 한다.
모델과 뷰를 연결하고 상호작용을 조정하는 역할이다. 사용자의 입력을 받아 모델을 업데이트하거나, 모델의 변화 상태를 뷰에 반영하는 등의 작업을 수행한다. 컨트롤러는 모델과 뷰 간의 중개자 역할을 하며, 사용자의 요청에 따라 애플리케이션의 동작을 제어한다.
일단 React는 MVC 패턴은 조금 다른 관점이다. React는 컴포넌트는 뷰의 역할을 수행하며, 상태와 속성을 사용하여 데이터를 관리하고 뷰를 업데이트한다. React에서는 별도의 컨트롤러가 없고, 컴포넌트 내부에서 상태를 처리하고 업데이트하는 방식을 취한다.
JavaScript 애플리케이션의 상태 관리를 위한 예측 가능한 상태 컨테이너 패턴이다. React롸 함께 가장 많이 사용되는 상태 관리 라이브러리 중 하나. 이 패턴은 애플리케이션의 상태를 중앙 집중식으로 관리하여 데이터 흐름을 효율적으로 제어하고 예측 가능한 상태 변화를 유지하기 위해 사용된다.
위 MVC 패턴과 비교해 보면, MVC 패턴에서는 View에서 사용자의 입력을 받으면 Controller로 가서 Model 부분에서 데이터를 조작하고 가공을 한다. 이와 같은 과정은 각 Model과 View들이 서로 상호작용을 하면서 거미줄같이 서로 얽히게 된다. 복잡해서 알아보기가 쉽지가 않다.
Action => Dispatcher => Store => View
Flux 패턴은 단방향 흐름을 보여준다. dispatcher, store, view는 각 input과 output이 있는 독립적인 역할을 한다.
모든 데이터는 dispatcher를 통해 흐른다. dispatcher에서 store로 흘러가며, store에서는 데이터를 변화시켜 view에서 데이터의 변화를 감지할 수 있는 변화 이벤트를 뱉는다. 이 변화 데이터는 view에서 사용가능.
이러면 복잡한 MVC 패턴보다 단순한 구조와 데이터 흐름을 볼 수 있다.
- UI
- Action
- Reducer
- Store
- State
UI에서 triggers를 작동하면 Actions으로 Reducer에 전달해서 Store에 update를 전달해서 State를 바꾼다.
애플리케이션의 상태를 보관하고 관리하는 객체. Action을 dispath하고 Reducer를 통해 상태를 업데이트 한다.
// index.js
import { legacy_createStore as createStore } from "redux";
import { Provider } from 'react-redux'
const store = createStore(rootReducer)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Provider 태그로 App을 감싸서 store 속성으로 creasteStore()를 넘겨 설정해준다. 그러면 App 안에서 store에 접근할 수 있다.
하지만 legacy_creatStore는 옛날 버전이고, 공부 목적으로만 사용하라고 권장한다.
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {}
})
Redux toolkit에서 configureStore를 권장한다.
애플리케이션에서 일어나는 어떠한 사건을 나타내는 일종의 객체다. Action은 상태 변화를 일으키기 위해 dispatch되며, 일반적으로 type과 payload 데이터 속성을 가지고 있다.
// action/index.js
// payload x
export const increase = () => {
return {
type: 'INCREASE',
};
};
// payload o
export const setNumber = () => {
return {
type: 'SET_NUMBER',
payload: num
}
}
Reducer로 Acrion을 전달해주는 함수. Dispatch의 전달 인자로 Action 객체가 전달된다.
dispatch( increase() )
dispatch( setNumber(1) )
const count = 1
const counterReducer = (state = count, action) => {
switch(action.type) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
case 'SET_NUMBER':
return action.payload
default:
return state;
}
}
dispatch를 통해 들어온 action을 type으로 걸러서 분기를 나눠주는 작업을 한다.
Reducer는 순수함수로 적어야 한다. 상태가 부수효과에 영향받지 않아야 하기 때문이다.
Redux를 사용할 때 활용할 수 있는 Hooks들을 제공한다. 그중 많이 사용되는 useSelector(), useDispatch()를 기억하자.
Action 객체를 Reducer로 전달해주는 Dispatch 함수를 반환하는 메서드.
import { useDispatch } from 'react-redux';
const dispatch = useDispatch()
dispatch( increase() );
dispatch( setNumber(1) );
컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드.
import { useSelector } from 'react-redux';
const counter = useSelector(state => state)
MDN MVC
https://developer.mozilla.org/ko/docs/Glossary/MVC#모델_뷰_컨트롤러_예시
In-Depth Overview, Flux 패턴
https://facebookarchive.github.io/flux/docs/in-depth-overview/