모델(Model)-뷰(View)-컨트롤러(Controller)의 약자.
사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다. 이러한 "관심사 분리" 는 더나은 업무의 분리와 향상된 관리를 제공한다.
Model이 변경되면 View를 업데이트하고, View에서 사용자 상호작용 등이 발생하면 Model을 업데이트하는 양방향 데이터 바인딩을 지원한다.
MVC 에 기반을 둔 몇 가지 다른 디자인 패턴으로 MVVM (모델-뷰-뷰모델), MVP (모델-뷰-프리젠터), MVW (모델-뷰-왓에버)가 있다.
MVC - MDN Web Docs
https://developer.mozilla.org/ko/docs/Glossary/MVC
<!-- html -->
<span id="display">0</span>
<button id="increment">Increment</button>
/*-------------------- JavaScript --------------------*/
// 모델
let count = 0;
function increment() {
count++;
}
function getCount() {
return count;
}
// 뷰
function render() {
document.getElementById('display').textContent = getCount();
}
// 컨트롤러
document.getElementById('increment').addEventListener('click', () => {
increment();
render();
});
프로젝트의 규모가 커질수록 수많은 Model과 View가 생성되고, Model과 View 사이에 엄청난 양의 데이터가 양방향으로 전달되게 된다. 이로 인해 데이터의 흐름을 예측하기가 점점 힘들어지고, 수많은 버그를 발생시키는 원인이 된다.
MVC 패턴의 문제를 해결하기 위해 2014년 페이스북에서 제안한 새로운 아키텍처로, React 애플리케이션에서 많이 사용된다.
Flux 패턴은 사용자 입력을 기반으로 Action을 생성하고, 이를 Dispatcher에 전달하여 Store의 데이터를 변경한 뒤 View에 반영하는 단방향의 데이터 흐름을 가진다.
Flux 패턴으로 구현된 프로젝트는 데이터가 단방향으로만 전달되기 때문에 데이터의 흐름을 파악하기가 용이하고, 그 결과를 쉽게 예측할 수 있다는 장점을 가진다.
사용자 입력 등의 상호작용으로 Action이 발생하면, Dispatcher에 전달되고 Store에 변경된 데이터를 쌓다가 한번에 View에 렌더링한다.
참고) Redux 개요 - TCP School
https://www.tcpschool.com/react/react_redux_intro
import React, { useReducer, useContext, createContext } from "react";
// 1️⃣ 액션 타입 정의
const ADD_TODO = "ADD_TODO";
// 2️⃣ 액션 생성 함수
const addTodo = (task) => ({
type: ADD_TODO,
payload: task,
});
// 3️⃣ Reducer (스토어 역할, 상태 변경 로직)
const todoReducer = (state, action) => {
switch (action.type) {
case ADD_TODO:
return { ...state, todos: [...state.todos, action.payload] };
default:
return state;
}
};
// 4️⃣ 전역 상태 관리를 위한 Context 생성
const TodoContext = createContext();
// 5️⃣ Provider 컴포넌트 (Flux의 Dispatcher 역할)
const TodoProvider = ({ children }) => {
const [state, dispatch] = useReducer(todoReducer, { todos: [] });
return (
<TodoContext.Provider value={{ state, dispatch }}>
{children}
</TodoContext.Provider>
);
};
// 6️⃣ View (컴포넌트)
const TodoApp = () => {
const { state, dispatch } = useContext(TodoContext);
const [task, setTask] = React.useState("");
const handleAdd = () => {
if (task) {
dispatch(addTodo(task)); // Dispatcher 역할 수행
setTask("");
}
};
return (
<div>
<h1>할 일 목록</h1>
<input value={task} onChange={(e) => setTask(e.target.value)} />
<button onClick={handleAdd}>추가</button>
<ul>
{state.todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
};
// 7️⃣ 앱 렌더링
import { createRoot } from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render(
<TodoProvider>
<TodoApp />
</TodoProvider>
);
useReducer와 리듀서 패턴
https://velog.io/@juwon98/React-useReducer