본문으로 건너뛰기
비공식 베타 번역

이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →

핵심 개념

애플리케이션의 상태가 평범한 객체로 표현된다고 상상해 보세요. 예를 들어 할 일 관리 앱의 상태는 다음과 같을 수 있습니다:

{
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}

이 객체는 '모델'과 유사하지만 설정 메서드(setter)가 없다는 점이 다릅니다. 이렇게 하면 코드의 다른 부분에서 상태를 임의로 변경할 수 없어 재현하기 어려운 버그가 발생하는 것을 방지할 수 있습니다.

상태의 무언가를 변경하려면 액션을 디스패치해야 합니다. 액션은 발생한 일을 설명하는 평범한 JavaScript 객체입니다(여기서 우리가 어떤 '마법'도 도입하지 않음을 주목하세요). 다음은 몇 가지 액션 예시입니다:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

모든 변경 사항을 액션으로 명시하도록 강제하면 애플리케이션에서 무슨 일이 일어나는지 명확히 이해할 수 있습니다. 무언가 변경되었다면 그 이유를 알 수 있습니다. 액션은 마치 발생한 일의 흔적과 같습니다. 마지막으로 상태와 액션을 연결하기 위해 리듀서라는 함수를 작성합니다. 다시 말하지만 여기에는 아무런 마법도 없습니다—리듀서는 단순히 상태와 액션을 인자로 받아 애플리케이션의 다음 상태를 반환하는 함수일 뿐입니다. 대규모 애플리케이션에서 이런 함수를 작성하는 것은 어려울 수 있으므로, 상태의 일부를 관리하는 더 작은 함수들을 작성합니다:

function visibilityFilter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_VISIBILITY_FILTER') {
return action.filter
} else {
return state
}
}

function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }])
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index
? { text: todo.text, completed: !todo.completed }
: todo
)
default:
return state
}
}

그리고 해당 상태 키에 대해 두 리듀서를 호출하여 애플리케이션 전체 상태를 관리하는 또 다른 리듀서를 작성합니다:

function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
}

이것이 기본적으로 Redux의 전체 아이디어입니다. 우리가 어떤 Redux API도 사용하지 않았음에 주목하세요. Redux는 이 패턴을 용이하게 하는 몇 가지 유틸리티를 제공하지만, 핵심 아이디어는 액션 객체에 대한 응답으로 상태가 시간에 따라 어떻게 업데이트되는지 기술하는 것이며, 여러분이 작성하는 코드의 90%는 Redux 자체, 그 API, 또는 어떤 마법도 사용하지 않은 평범한 JavaScript입니다.