codestates / codestates/SoundBubble
[Dev_Log] 8/24 (화) 김재우
- Dominant language
- TypeScript
- Stars
- 3
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
### 오늘은 어떻게 프로젝트에 기여했나요?
* 유저 가입 타입에 따라 비밀번호 입력 input 엘리먼트 비활성화
소셜 로그인으로 가입한 유저는 기본적으로 비밀번호를 사용하지 않는다. 원래 닉네임 변경, 비밀번호 변경 기능에는 이전 비밀번호를 입력해야하는데, 소셜 로그인 유저의 경우에 해당 비밀번호 input 엘리먼트에 disable 속성을 주고 플레이스 홀더 문구를 다르게 표기하여 사용자가 입력하지 않아도 된다는 것을 명시했다. 그리고 비밀번호 변경에서 새롭게 비밀번호를 등록하면 통합(intergration) 유저로 변경되며, 기존 비밀번호를 입력할 수 있게 되고 일반 로그인도 사용할 수 있다.
* 리덕스 리팩토링
상태의 초기 값을 수정하여 유저 정보를 하나의 객체로 묶고 토큰과 분리하였다. 이에 맞추어 리듀서 또한 유저 리듀서, 토큰 리듀서로 분리하였고, 전체적으로 리덕스 액션 타입과 타입 생성 함수를 새로 정의하였다.
* Axios 인터셉터 등록
액세스 토큰을 보내는 요청, 즉 인증이 필요한 요청은 서버에서 토큰의 검증을 거치고 만료되었을 경우 리프레시 토큰을 이용해 새롭게 액세스 토큰이 발급된다. 클라이언트에서는 응답 헤더에 토큰이 있으면 갱신해야 하는데 모든 Axios 요청마다 then 메소드 내부에 같은 코드를 입력하는 것은 굉장히 비효율적이다. Axios 인터셉터는 서버에 요청을 보내기 전 직전, 응답이 온 직후에 요청이나 응답을 가로채서 언제나 동일한 코드를 수행할 수 있다. 응답 인터셉터에 응답 헤더에 토큰이 있으면 dispatch 호출을 하고, 401 에러가 오면 강제로 로그아웃하는 코드를 추가했다. 이제 인터셉터를 적용한 axios 인스턴스를 일반 axios 대신 사용하면 된다.
### 오늘의 프로젝트에서 배운 점은 무엇인가요?
* Axios 인터셉터 등록
먼저 axios 인스턴스를 생성한 뒤 axios에서 제공하는 방법에 따라 항상 실행할 코드를 추가하면 된다. 인터셉터를 거친 뒤에는 then 또는 catch 메소드로 넘겨진다.
```js
//* axios 인스턴스 생성
const axiosInstance: AxiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
timeout: 1000,
});
//* 응답 인터셉터 등록
axiosInstance.interceptors.response.use(
function (res: AxiosResponse) {
// 응답 받은 직후에 실행되는 코드
if (res.headers.authorization) {
const newAccessToken: string = res.headers.authorization.split("Bearer ")[1];
dispatch(setAccessToken(newAccessToken));
}
return res;
},
function (err: AxiosError) {
// 에러가 발생한 직후에 실행되는 코드
if (err.response && err.response.status === 401) {
alert("로그인 상태가 만료되었습니다. 재로그인 해주세요");
dispatch(removeUserInfo());
dispatch(removeAccessToken());
window.location.replace("/login");
}
return Promise.reject(err);
},
);
```
### 오늘의 프로젝트에서 힘든 점은 무엇인가요?
* 리덕스 타입 정의
타입스크립트는 강력한 타입 추론, 자동 완성 기능으로 개발자를 돕는다. 하지만 리덕스의 경우 액션과 리듀서에서 올바른 추론을 사용하려면 설정이 조금 까다롭다. 액션 생성 함수의 리턴 타입(액션 객체)을 정의하는 것이 힘들었는데 stackoverflow의 도움을 받고 제네릭 타입을 이용해서 해결하였다. IAction을 액션 타입과 페이로드를 받는 제네릭 타입으로 정의하고 액션 생성 함수의 리턴 값으로 지정한다. 해당 액션 생성 함수가 리턴하는 액션 객체의 타입과 페이로드를 <>안에 지정하면 된다.
```js
// @type/redux.d.ts 파일
//* 타입: 액션 생성 함수의 반환 값 (액션 객체)
export interface IAction {
type: T; // 액션 타입에도 제네릭을 등록해야 리듀서에서 타입 추론이 제대로 동작한다
payload: P;
}
//* 타입: 액션 생성 함수의 반환 payload 값 (액션 payload)
export type PayloadUserInfo = { userInfo: UserInfo };
export type PayloadToken = { accessToken: string };
// actions/index.ts 파일
//? 액션 타입 선언
export const SET_USER_INFO = "SET_USER_INFO";
export const REMOVE_USER_INFO = "REMOVE_USER_INFO";
//? 액션 생성 함수 정의
//* 유저 정보 저장
export const setUserInfo = (userInfo: UserInfo): IAction => {
return {
type: SET_USER_INFO,
payload: { userInfo },
};
};
//* 유저 정보 삭제
export const removeUserInfo = (): IAction => {
return {
type: REMOVE_USER_INFO,
payload: null,
};
};
// reducers/userReducer.ts 파일
const userReducer = (state = initialState, action: UserAction): InitialState => {
switch (action.type) {
case SET_USER_INFO:
const userInfo: UserInfo = action.payload.userInfo;
// payload에 userInfo가 있는 것이 유추된다
return Object.assign({}, state, {
user: userInfo,
});
case REMOVE_USER_INFO:
// action.payload.까지 입력해도 아무 것도 유추되지 않는다
return Object.assign({}, state, {
user: initialState.user,
});
// ...
```
[참고한 stackoverflow 글](https://stackoverflow.com/questions/35482241/how-to-type-redux-actions-and-redux-reducers-in-typescript)
### 내일은 프로젝트에 기여하기 위해 무엇을 해야 하나요?
* [ ] Portal을 이용한 모달 알림창 학습 및 구현
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.