본문 바로가기

archive/Project

[MainProject] day-13 (5/17)

오늘의 할 일

1. 숙제마무리

2. 태그선택 아직도 안끝냈다고?

3. 제출하는 것도 아직 문제가 있다고?

4. 오늘 자기 전까지 검색기능만 완성해보자.

5. 화이팅..!!

 

#1 숙제 마무리

... 어제에 이어 계속되는 과제를 마무리해보자.

어제 새벽에 문제를 찾느라 고생해서 눈물이 날 것 같았다. 커다란 문제들은 해결했고 이제.. 또다른 큰(?)문제인 리덕스 툴킷이 남았다. dispatch로 각각 해당되는 정보만 업데이트해주면 되는데..

 

dispatch를 할 때 전체 객체를 다시 보내서 업데이트 하는 것이 아닌 현재 바뀌는 부분에 대한 정보만 보내서 상태 객체 중 해당부분만 업데이트하고싶어서 코드를 짜던 중 슬라이스에서 오류가 났다.

const signupSlice = createSlice({
  name: 'signup',
  initialState: { ...initialStateSignup },
  reducers: {
    setSignupInfo(state, action) {
      state = {...state, action.payload};
    },
    clearSignupInfo() {
      return initialStateSignup;
    }
  }
});

setSignupInfo {} 안에 있는 action.payload 부분에서 오류가 났는데, type 오류였다. 그래서 어제 배워온 뤼튼~~에게 물어봤는데 답변은 이러했다.

setSignupInfo 리듀서에서 오류가 발생하는 이유는 action.payload가 전체 상태 대신, 키와 값 (property and value)을 가지고 있는 개체로 전달되었기 때문입니다. 상태를 적절하게 병합하려면, 리듀서에서 스프레드 연산자를 사용하지 않고, Immer 라이브러리 내장 기능을 사용해 다음과 같이 작성할 수 있습니다.

const signupSlice = createSlice({ 	
  name: 'signup', 
  initialState: { ...initialStateSignup }, 
  reducers: { 
    setSignupInfo(state, action) {
    // action.payload는 { key: 'username', value: 'newUsername' }와 같은 형식이여야 함 
    const { key, value } = action.payload; 
    state[key] = value; 
    }, 
    
    clearSignupInfo() { return initialStateSignup; }, 
  }, 
});


setSignupInfo 리듀서의 수정된 코드에서는 action.payload가 키-값 쌍 객체 (예 : { key: 'username', value: 'newUsername' })를 받아야하며, 이러한 객체가 해당 키에 대한 상태를 설정하고 Immer 라이브러리가 자동으로 일부를 병합하여 상태를 변경합니다.

이제 리듀서를 사용하여 상태를 업데이트할 때, 다음과같이 작성할 수 있습니다:
dispatch(setSignupInfo({ key: "username", value: "newUsername" }));​

이렇게 하면 username만 업데이트하고 나머지 상태를 보존할 수 있습니다. 이를 위해 코드의 다른 부분에서 객체 키와 값을 생성한 후 setSignupInfo액션에 추가하십시오.

문제는 키:값 쌍의 형태로 데이터가 주어져야만 하는데 action.payload는 현재 any 타입으로 되어있는 것이 문제였다. 그렇다고 action의 타입을 임의대로 바꾸거나 action.payload의 타입을 바꾸는 방법은 떠오르지 않았는데, 

이 부분도 뤼튼님이 도와주셨다. keyof를 사용해서 key의 값을 username 등 객체의 key값으로 제한해주고 싶었는데 어떻게 정확하게 사용해야하는지 짚어줘서 keyof typeof를 책에서 공부했던 것이 기억나서 바로 이해도되고 거리낌없이 적용할 수 있었다. 변경된 코드는 다음과 같다.

setSignupInfo(state, action: PayloadAction<{ key: keyof typeof initialStateSignup; value: string }>) {
      const { key, value } = action.payload;
      state[key] = value;
    }

이제 dispatch가 잘되는지 확인해보도록 하자.

여기서 잠깐 Typescript를 쓰는 보람을 느껴보면... reducer에서 어떻게 사용해야할지 막막하게 만들어서 절망을 주지만(뤼튼이 바로 해결해줘버렸기에 평소와 같이 절망을 느끼지는 않았다) 아래와 같이 dispatch로 페이로드를 잘못보내는 경우에 오류를 띄워줘서 undefined가 발생하는 일을 막아주는 점이 너무 좋다.

이렇게 정확하게 코드를 적어주어야만 오류가 안나도록 도와준다.

if(validationType === 'username') dispatch(setSignupInfo({key:'username', value:e.target.value}))

key: ~~, value: ~~ 이 형태는 물론이고, keyof typeof를 사용했기에 없는 key값을 입력하는 것도 막아준다.

'passwor' 이라고 잘못적으면 오류가 나는 모습이다.

 

email, password 가 자동완성 되자마자 스토어에 dispatch를 잘날리는 모습이다

 

닉네임을 입력하니 다음과 같이 이벤트가 3번 일어나면서 가장 최근에 날린 dispatch 내용이 의도한 바와 정확히 일치함을 다시 확인할 수 있다.

 

자 이제.. 회원가입 버튼을 눌렀을 때 useSelector로 저장된 상태를 가져와서 잘 보내지기만 하면 된다.

 

여기서 또 오류가 있었는데 간략하게 요약해보면 useSelector를 사용할 때, 함수 컴포넌트 안에서 사용하되 일반 함수 안에서는 사용하면 안되는데 onClickhandler 안에서 사용해서 오류가 났다. 좀 답답했던 상황이 있었는데 새로고침만 일어나고 error 메세지나 콘솔로그도 없어서 무슨일인가 싶었다. 다행히도 뤼튼덕에 원인도 제대로 파악하고 해결할 수 있었다.

 

onClickhandler함수를 별도의 파일로 빼서 관리하고 싶은데 useSelector나 useNavigate를 인자로 전달을 해주어야할까? > 팀원들과 회의에서 이야기나눈 결과 답은 YES인 것 같다. 이하 고도화작업에 이 부분도 하고 넘어가도록 해야겠다.

 


 

현재 회원가입, 로그인 정상작동되게 해놓았고 상태관리도 InputContainer에서 useInput 사용하는 것으로 정리되었다.

밀린 커밋들을 쭉 날리고... 부가적인 리펙토링은 오늘 마지막에 하려고 하였으나, 팀원들이 더 사용하기 좋게 만드는 것이 좋다고 의견이 나와서 그 부분만 수정하고 다른 기능으로 넘어가려고 한다.

 

프론트엔드 회의 후에 변경된 작업 순서:

1) react.persist 스토어 별로 적용하기(급하면 일단 모든 스토어 저장하기)

2) useInput 재사용성 더욱 높이기(고도화작업)

3) 태그선택 부분부터 원래 하려던 목차대로

 

4) 발견된 버그 : 회원가입,로그인 시 버튼을 누르면 정상동작되지만, 엔터를 누를경우 Oauth로그인이 아닌 경우인데 Oauth로 가짐.

...

1) redux-persist

이제는 정말 해야한다. 검색은 그만하고 바로 적용해보기로 하였다. 새로고침 후에 store에 원하는 상태값이 남아있으면 성공이다. 로그인을 성공하였을 때 user의 기본정보가 날아오는데 memberId 같은 경우는 마이페이지로 접근할 때 url에도 적고 api 요청을 날릴 때도 필요한 정보라서 새로고침이 일어나는 경우에도 유지하도록 하려고한다. 그리고 현재 회원가입,로그인 input value도 store에 저장되도록 했기 때문에 현재 서버통신이 안되므로 이것들로 테스트 해볼 수도 있다. 

 

그런데...!!! 정말 근본적인 의문이 생겨서 redux-persist를 적용하는 것은 보류하기로했다. 필요한 정보는 로컬이나 세션에 저장하면 된다..!! 로그인 유지기능도 체크할 경우 로컬에 저장하고 아닌 경우에는 세션에 저장하여 브라우저를 닫으면 다시 로그인하도록 구현하면 된다. redux-persist도 로컬이나 세션에 선택해서 저장할 수 있고 초기화되는 기본메커니즘은 동일하다.

 

그럼 redux-persist 왜 쓰는데..? 

로그인 유지 기능을 구현하거나 암호화와 같은 기능을 사용하지 않는 경우 redux-persist를 사용할 필요가 없습니다. localStorage는 여전히 데이터를 저장하는 좋은 방법입니다.
그러나 redux-persist를 사용하면 몇 가지 추가 이점이 있습니다. 예를 들어, redux-persist를 사용하여 데이터를 압축하여 저장 공간을 절약할 수 있습니다. 또한 redux-persist를 사용하여 데이터를 암호화하여 보안을 강화할 수 있습니다.
궁극적으로 redux-persist를 사용할지 여부는 앱의 특정 요구 사항에 따라 다릅니다.

사실, 로그인 유지도 위에서 생각해본 것처럼 구현이 가능하기 때문에 특별히 사용할 이유가 현재는 없다. 억지로 새로운 기술을 적용하는 것은 지양하고 쓸 이유를 찾아서 적용하도록 하자. 다른 할 일이 많다..!! 로컬에만 branch를 살려두고(publish를 안해서 remote에는 안보이도록 하려고한다.) 나중에 시간이되면 다시 작업해야겠다.

 

2) 태그 선택하는 부분 스타일, 기능

이 부분을 작업을 분명 했는데 블로그에 업데이트를 안해놓았다. 커밋내역을 뒤져서 5/17에 한 작업이 무엇인지 업데이트를 해보겠다..ㅋㅋㅋㅋ