View
Redux thunk
하고자 했던 것
로그인 시 token을 받아오고 그 token을 session Storage에 저장해 둔다.
또 하나 해야 할 일은 userId(인공키) 값을 전역 state에 저장해서 유저 관련 정보가 필요한 컴포넌트마다 사용하게 해야 하고, isLoggedIn 또한 전역 state에 저장하여 true 값이 유지되게 해야 한다.
이 기능을 구현하기 위해 redux를 사용했다.
아직 api 컨벤션을 사용하지 않아서 login api (아이디, 비밀번호로 request를 보내면 userid와 token을 response로 받는다)를 action 생성 함수에서 axios로 실행하고, 액션을 return 해 주었는데...
문제
어쩐지 sessionStorage에 저장만 되고... isLoggedIn도 true로 안 바뀌고 home으로 넘어가지지도 않았다.
useEffect()를 사용하여 isLoggedIn 이 바뀔 때마다 리렌더링을 시도했지만 그 문제는 아니었다. 아예 isLoggedIn이 바뀌지 않았던 것!
내가 처음에 작성했던 코드
export const login = ({ loginId, password }) => {
axios
.post(
"/api/auth/login",
{ loginId, password },
{
headers: { "Content-Type": `application/json` },
}
)
.then((response) => {
if (response.headers.authorization && response.data) {
sessionStorage.setItem("access-token", response.headers.authorization);
console.log(response.data);
return {
type: LOGIN,
userId: response.data,
};
});
const token = sessionStorage.getItem("access-token");
const initialState = token ? { isLoggedIn: true } : { isLoggedIn: false };
const user = (state = initialState, action) => {
switch (action.type) {
case LOGIN:
case LOGIN_SUCCESS:
return {
isLoggedIn: true,
userId: action.userId,
};
default:
return state;
}
로그인 컴포넌트에서 dispatch(login({loginId, password}))를 실행 후 navigate("/home") 을 해 주었는데 위의 문제가 생긴 거였다.
나의 잘못
1. 액션 생성 함수에서의 잘못은 then() 안에서 액션을 리턴한다는 것이었다.
then()은 promise를 리턴하여 계속해서 체이닝 할 수 있는 함수다. (이 부분은 더 공부가 필요할 듯하다 - https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
그러니까 나는 별 말도 안되는 걸 하면서 액션을 일으키려고 했던 거였다.
2. redux에서 비동기 통신은 미들웨어를 거쳐야 한다.
1번은 해결했으나 여전히 userId가 state에 담기지 않았다. console.log() 찍어 확인해 보니 비동기가 제대로 먹히지 않았음.
해결
미들웨어는 객체 대신 함수를 생성하는 액션 생성 함수를 작성할 수 있게 해 준다.
리덕스에서는 기본적으로 액션 객체를 디스패치 한다.
const actionCreator = (payload) => ({action: 'ACTION', payload});
하지만 비동기 통신으로 인해 특정 액션이 통신을 받아온 이후에 이루어져야 한다면 일반 액션 생성자로는 할 수 없으므로 미들웨어인 thunk를 써야 하는 것이었다.
thunk 함수에서는 dispatch를 파라미터로 받아올 수 있음. (아마 thunk에서 제공하는 기능인듯..)
export const login =
({ loginId, password }) =>
async (dispatch) => {
const data = await axios
.post(
"/api/auth/login",
{ loginId, password },
{
headers: { "Content-Type": `application/json` },
}
)
.then((response) => {
if (response.headers.authorization && response.data) {
sessionStorage.setItem(
"access-token",
response.headers.authorization
);
return response;
}
});
console.log(data);
dispatch({
type: LOGIN_SUCCESS,
userId: data.data,
});
};
그렇게 해서 dispatch 통해 액션을 실행해 준다. 이 액션은 리듀서로 이동해 isLoggedIn도 true로 만들어 주고, userId도 저장해 준다!
'Front-End > React' 카테고리의 다른 글
[Trouble-Shooting] persist로 저장되어 있는 redux state에 field가 추가되는 경우 (0) | 2022.09.22 |
---|---|
Redux 기초 - 노션 백업 (0) | 2022.03.06 |
React 기초 - 노션 백업 (0) | 2022.03.06 |