리덕스 : 상태 관리의 로직을 컴포넌트 밖에서 처리하는 방법
리덕스를 적용한 구조는 위의 이미지와 같습니다. 모두 스토어에서 관리하고 동작하죠
여기서 나오는 용어를 간단히 정리해 보자면
스토어: 애플리케이션 상태 값들을 내장
액선: 상태 변화를 일으킬 때 참조하는 객체
디스패치: 액션을 스토어에 전달
리듀서: 상태를 변화시키는 로직이 있는 함수
구독: 스토어 값이 필요한 컴포넌트는 스토어를 구독(계속해서 스토어를 본다는 의미)
그럼 이제 사용 하는 방법을 알아보아야겠죠?
리덕스는 리액트에서 사용하려고 만든 라이브러리지만 리액트에 의존하지않아서 리액트를 사용하지 않아도 독자적으로 사용이 가능합니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>ITSkeleton</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.js"></script>
</body>
</html>
이렇게 HTML로 작성해서 불러올 수 있습니다
<script>
console.log(Redux);
</script>
를 해서 한번 확인해보면
콘솔창에 다음과 같이 잘 나오는지 확인해 봅시다!
저는 JSBin을 이용해서 확인해 보았습니다
* 액션
액션은 스토어에서 상태변화를 일으킬때 참조하는 객체입니다.
이 객체는 꼭 type을 가지고 있어야 하는데요
이 타입은 액션이 어떤 작업을 하는 액션인지를 정의하고 대문자와 밑줄로 조합하여 만들어집니다.
{
type: 'TODO',
todo: {
num: 1,
name: 'ITSkeleton',
isCheck: false
}
}
// 객체의 형태
const TODO = 'TODO';
const todo = (diff) => ({
type: TODO,
diff: diff
});
이러한 형식으로 존재 합니다. 위는 참고만 하는 것으로 보시면 좋습니다.
* 리듀서
리듀서는 상태에 변화를 일으키는 함수 입니다. 리듀서는 파라미터를 두개를 받고, 첫번째는 현재상태, 두번째는 액션 객체로 이루어져 있습니다.
const initialState = {
number: 0,
txt: 'num'
};
function counter(state = initialState, action) {
switch(action.type) {
case INCREMENT:
return Object.assign({}, state, {
number: state.number + action.diff
});
case DECREMENT:
return Object.assign({}, state, {
number: state.number - action.diff
});
default:
return state;
}
}
아래에서 사용될 코드를 미리 가져왔습니다.
기본적으로 리덕스에서 상태를 업데이트 할때에는 state를 직접적으로 건드리면 절대 안됩니다. 새로운 객체를 만들어 그 안에서 상태를 정의해야 합니다. number: state.number - action.diff 와 같은 코드
Object.assign 함수는 파라미터로 전달된 객체들을 순서대로 합쳐 줍니다.
물론 쓰지 않고
{
number: 1,
test: {
txt: 'num',
number: 2
}
}
이러한 객체가 있을경우
function counter(state = initialState, action) {
switch(action.type) {
case INCREMENT:
return {
// number: state.number + action.diff
number: state.test.number + action.diff
};
case DECREMENT:
return {
// number: state.number - action.diff
number: state.test.number - action.diff
};
default:
return state;
}
}
이렇게 적을 수도 있습니다.
* 리덕스 스토어 생성
액션과 리듀서가 준비되면 리덕스 스토어를 만들 수 있습니다.
const { createStore } = Redux;
이렇게 정의할 수 있습니다.
* 구독
스토어의 상태가 변할때마다 특정 함수를 실행 시킵니다.
const subscribe = store.subscribe(() => {
console.log(store.getState()); // store의 state값을 가져와서 console에 띄웁니다.
});
스토어를 구독할 때는 subscribe 함수를 사용합니다. 이 함수는 함수 형태의 파라미터를 받고 파라미터로 전달된 함수는 스토어 상태가 변할때마다 호출됩니다
* dispatch
이 함수는 스토어에 액션을 넣을때 사용되는 함수 입니다. 이 디스패치를 꼭 해주어야 구독할때 적었던 함수가 실행됩니다.
store.dispatch(todo(3));
이렇게 호출 하면 됩니다. 더 자세하게 짜는 방법은 아래에서 적도록 하겠습니다.
간단히 숫자를 더하고 빼는 리덕스 전체를 한번 만들어 보겠습니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>ITSkeleton</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.js"></script>
</body>
</html>
HTML은 위와 같습니다
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const increment = (diff) => ({
type: INCREMENT,
diff: diff
});
const decrement = (diff) => ({
type: DECREMENT,
diff: diff
});
const initialState = {
number: 0
};
function counter(state = initialState, action) {
switch(action.type) {
case INCREMENT:
return { number: state.number + action.diff };
case DECREMENT:
return { number: state.number - action.diff };
default:
return state;
}
}
const { createStore } = Redux;
const store = createStore(counter);
const unsubscribe = store.subscribe(() => {
console.log(store.getState());
});
store.dispatch(increment(1));
store.dispatch(decrement(5));
store.dispatch(increment(10));
스크립트를 위와 같이 적어줍니다.
그러고 실행을 해보면 콘솔창에
이렇게 나온다면 정상적으로 만들어진 것입니다!
그리고 리덕스에서는 무조건 지켜야할 규칙 같은것이 존재하는데요
1. 스토어는 한개만!
2. state는 읽기만!
3. 변화는 함수로 구성!