리덕스 스토어 state를 수정하는 방법을 배웠다.
1.View 에서 액션이 일어난다.
2. dispatch 에서 action이 일어나게 된다.
3. action에 의한 reducer 함수가 실행되기 전에 middleware가 작동한다.
4. middleware 에서 명령내린 일을 수행하고 난뒤, reducer 함수를 실행한다. (3, 4번은 아직 몰라도 됩니다!)
5. reducer 의 실행결과 store에 새로운 값을 저장한다.
6. store의 state에 subscribe 하고 있던 UI에 변경된 값을 준다.
리덕스흐름
우리가 useState()를 사용해서 number에 +1을 할 때는 setNumber을 이용해서 +1을 해주었습니다.
// 예시 코드
// local state
const [number, setNumber] = useState(0)
// click handler
const onClickHandler = () => {
setNumber(number + 1)
}
값의 수정은 리듀서에서 일어난다.
counter.js 모듈에 있는 number에 +1을 하고 싶으면
1. 리듀서에게 보낼 number를 +1 하라는 “명령”을 만든다.
2. 명령을 보낸다.
3. 리듀서에서 명령을 받아 number +1을 한다.
// 예시 코드
//number에 +1 을 하는 액션 객체
{ type : "PLUS_ONE" };
액션객체를 보내기 리듀서로 보내기위해서는 새로운 훅을 사용해야 합니다. 그 훅은 useDispatch
라는 훅 입니다. react-redux에서 import 해서 사용할 수 있으며, 우리가 만든 액션 객체를 리듀서로 보내주는 역할을 하는 훅입니다.
useDispatch
라는 훅을 사용하기 위해서는 컴포넌트 안에서 아래와 같이 먼저 코드를 작성해서 dispatch
라는 변수를 생성해줘야 합니다. 이렇게 생성한 dispatch는 함수
라는 점을 기억하세요! 그래서 우리는 dispatch를 사용할 때 ()
를 붙여서 함수를 실행하게 됩니다.
// src/App.js
import React from "react";
import { useDispatch } from "react-redux"; // import 해주세요.
const App = () => {
const dispatch = useDispatch(); // dispatch 생성
return (
<div>
<button>+ 1</button> {/* 버튼을 하나 추가해주세요. */}
</div>
);
};
export default App;
dispatch를 사용할 때 ( ) 안에 액션객체를 넣어주면 됩니다. 만약 어떤 버튼을 클릭했을 때 리듀서로 액션객체를 보내고 싶다면 아래와 같이 코드를 작성합니다.
// src/App.js
import React from "react";
import { useDispatch } from "react-redux"; // import 해주세요.
const App = () => {
const dispatch = useDispatch(); // dispatch 생성
return (
<div>
<button
// 이벤트 핸들러 추가
onClick={() => {
// 마우스를 클릭했을 때 dispatch가 실행되고, ()안에 있는 액션객체가 리듀서로 전달된다.
dispatch({ type: "PLUS_ONE" });
}}
>
+ 1
</button>
</div>
);
};
export default App;
디스패치를 이용해서 액션객체를 리듀서로 보낼 수 있습니다. 만약에 어떤 컴포넌트가 렌더링 됐을 때 액션객체를 리듀서로 보내고 싶다면 어떻게 해야 할까요? 한번 고민해보시길 바랍니다.
// src/redux/modules/counter.js
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
리듀서에 action을 콘솔로 찍어보겠습니다.
// src/redux/modules/counter.js
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
console.log(action); // 여기에 console.log(action) 추가
switch (action.type) {
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
이제 액션객체를 잘 보내고, 잘 받고 있음을 확인했으니 state에 있는 number를 실제로 변경하는 로직 코드를 구현해볼게요. 로직코드는 리듀서 안에 있는 switch문
작성됩니다.
리듀서가 액션객체를 받아 상태를 바꾸는 원리는 아래와 같습니다.
1. 컴포넌트로부터 dispatch를 통해 액션객체를 전달 받는다.
2. action 안에 있는 type을 스위치문을 통해 하나씩 검사해서, 일치하는 case를 찾는다.
3. type과 case가 일치하는 경우에, 해당 코드가 실행되고 새로운 state를 반환(return) 한다.
4. 리듀서가 새로운 state를 반환하면, 그게 새로운 모듈의 state가 된다.
1. 컴포넌트로부터 dispatch를 통해 액션객체를 전달 받는다.
까지 구현했으니, 2~4를 한번 직접 코드로 작성해보겠습니다.
// src/modules/counter.js
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
console.log(action);
switch (action.type) {
// PLUS_ONE이라는 case를 추가한다.
// 여기서 말하는 case란, action.type을 의미한다.
// dispatch로부터 전달받은 action의 type이 "PLUS_ONE" 일 때
// 아래 return 절이 실행된다.
case "PLUS_ONE":
return {
// 기존 state에 있던 number에 +1을 더한다.
number: state.number + 1,
};
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
action이 {type: “PLUS_ONE”}
이기 때문에, 리듀서 안에 있는 스위치문은 action.type을 조회합니다. 그리고 그것이 일치하면 return
절이 실행되고 새로운 state를 반환합니다. 막상 글로 보면 복잡해보였지만, 코드로 보면 스위치문에 case를 하나 추가해주는 것으로 완료됩니다.
자, 이제 우리가 dispatch를 통해 액션객체를 App.js 컴포넌트에서 보냈고, 그것을 리듀서에서 받아 스위치문을 통해 조건을 찾았고, 그에 해당했을 때 state값을 변경하는 로직까지 모두 구현했으니 한번 정말 state가 잘 변경되는지 확인해봅시다.
// src/App.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
const App = () => {
const dispatch = useDispatch();
// 👇 코드 추가
const number = useSelector((state) => state.counter.number);
console.log(number); // 콘솔 추가
return (
<div>
{/* 👇 코드 추가 */}
{number}
<button
onClick={() => {
dispatch({ type: "PLUS_ONE" });
}}
>
+ 1
</button>
</div>
);
};
export default App;