리덕스는 Javascript 애플리케이션에서 상태(state)를 예측 가능하고 관리하기 쉽게 만들어주는 상태 관리 라이브러리이다. 리덕스는 React와 함께 사용되는 경우가 많다.
단일 소스 원칙(Single source of truth) : 리덕스에서는 앱의 전체 상태가 단일 객체 트리로 표현되며, 스토어(store)에 저장된다. 이 객체 트리는 앱에서 공유되는 상태의 단일 원천이 된다.
단일 객체 트리란?
애플리케이션의 상태를 단일 객체 안에 저장하는 것을 의미한다. 이 객체는 자바스트립트 객체로, 애플리케이션의 모든 상태가 포함된다. 이 객체 안에는 다양한 데이터가 들어갈 수 있으며, 이 데이터는 여러 컴포넌트에서 공유되어 사용된다.단일 객체란?
하나의 객체가 여러 속성을 가지고 있는 것을 말한다. 이 객체 안에는 여러 가지 데이터나 값을 담을 수 있으며, 다향한 속성을 통해 이 데이터를 구분하거나 조작할 수 있다.
상태 읽기 전용이다.(State is read-only) : 상태는 액션(Action)을 통해서만 업데이트 할 수 있으며, 상태를 직접 수정할 수 없다. 액션을 객체로 표현되며, "type"속성을 필수적으로 가지고 있어야한다.
변화는 순수 함수로 작성되어야한다.(Changes are made with pure functions) : 리듀서는 현재 상태와 액션을 인자로 받아서 새로운 상태를 반환하는 순수 함수로 작성되어야 한다.
순수 함수란?
- 예측 가능성 : 같은 인자가 주어지면 항상 같은 결과를 반환한다.
- 외부 상태 변경 없음 : 함수 내부에서 함수 외부의 어떤 상태도 변경하지 않는다.
- 독립성 : 다른 부분에서 영향을 받지 않고 독립적으로 동작한다.
type
속성을 가지고 있어야 한며, 필요에 따라 payload
속성을 추가할 수 있다.todos.js 파일:
// 액션 타입(Action Types)
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
// 액션 생성자(Action Creators)
function addTodoAction(text) {
return { type: ADD_TODO, text };
}
function toggleTodoAction(index) {
return { type: TOGGLE_TODO, index };
}
// 초기 상태 정의(Initial State)
const initialState = {
todos: []
};
// 리듀서(Reducer)
function todosReducer(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
};
case TOGGLE_TODO:
return {
todos: state.todos.map((todo, index) => {
if (index === action.index) {
return {
...todo,
completed: !todo.completed
};
}
return todo;
})
};
default:
return state;
}
}
// 스토어(Store)
const store = Redux.createStore(todosReducer);
export default store;
export { addTodoAction, toggleTodoAction };
index.js 파일:
import store, { addTodoAction, toggleTodoAction } from './todos';
store.dispatch(addTodoAction('Buy milk')); // { todos: [{ text: 'Buy milk', completed: false }] }
store.dispatch(toggleTodoAction(0)); // { todos: [{ text: 'Buy milk', completed: true }] }
컨텍스트란 React 컴포넌트 트리 안에서 전역적으로 데이터를 공유하는 방법을 제공하는 React API이다. 컨텍스트를 사용하면 모든 컴포넌트에서 명시적으로 props를 통해 데이터를 전달하지 않고도 값을 전달하거나 상태를 업데이트할 수 있다.
컨텍스트는 Provider
와 Comsumer
라는 두가지 요소로 이루어져 있다. Provider는 컴포넌트 트리의 상위 컴포넌트에서 사용되며, 값을 제공한다. Consumer(권장하지 않음)는 Provider의 값을 구독하는 컴포넌트이다.
예를 들어, 언어 설정이나 로그인 정보와 같이 애플리케이션 전역에서 사용되는 데이터를 공유할 때 컨텍스트를 사용할 수 있다.
예시
상위 컴포넌트
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
하위 컴포넌트
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increaseCount, decreaseCount } from './actions';
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increaseCount())}>Increase</button>
<button onClick={() => dispatch(decreaseCount())}>Decrease</button>
</div>
);
}
export default Counter;