발생 : 내가 로컬 브랜치를 커밋한 때 remote에서 다른 팀원이 merge
→ 우선 로컬 develop으로 pull
→ 로컬 브랜치에서 pull 받으려는 중
오류 메시지 :
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
1) fast-forward only
즉 둘 중 한 곳에만 commit이 있을 경우 pull을 허락한다. 원격과 로컬 모두 새 commit이 있다면(=원격저장소에서 pull을 받아오지 않고 로컬에서 새 커밋을 했다면) git pull이 불가하다.
pull 받아야 해서 이 옵션은 기각.
2) rebase
커밋 히스토리 정리에 자주 쓰이는 명령어다. 원격 브랜치의 마지막 commit으로 로컬 브랜치의 상태를 되돌린다.
되돌릴 것 없이 그냥 합치기만 되어서 패스.
3) merge
말 그대로 브랜치끼리 합친다. git pull 받을 때 merge commit이 필수. 이 방식을 선택했다.
git config pull.rebase false
터미널 입력git push origin 로컬 브랜치명
Shift + :wq
로 exit)git config
로 지금 리포에선 merge가 기본 옵션으로 적용되었다.
Promise {<pending>}
(= 아직 처리 중)const res = await response.json()
마이페이지
회원가입 후 로그인 후 메인 화면
🐞 엔터키 적용하자
🐞 로그인 실패 시 안내 문구 보여주기
오늘은 거의 회원가입, 로그인 컴포넌트들만 수정했다.
const [isFormValid, setIsFormValid] =useState(false);
const idValue = watch('id');
const pwValue = watch('pw');
useEffect(() => {
const isIdValid = idValue.trim() !== '';
const isPwValid = pwValue.trim() !== '';
const isFormValid = isIdValid && isPwValid;
setIsFormValid(isFormValid);
}, [idValue, pwValue]);
useEffect를 사용하면 특정 시점에 특정 동작이 가능하도록 로직을 설계할 수 있다. 그래서 id와 pw의 value가 바뀔 때마다 각각의 값이 빈값인지 확인(isIdValid
, isPwValid
)하고 두 필드 모두 빈값이 아닐 때만 true를 반환하도록 한다.
버튼에 해당 내용을 disabled 조건으로 걸어두면 완료.
<button
type="submit"
className="signButton"
disabled={!isFormValid}
>
로그인
</button>
이렇게 해결되는 줄 알았으나, 또 다른 문제가 발생!
1-2. trim 타입 에러
Cannot read properties of undefined (reading 'trim')
TypeError: Cannot read properties of undefined (reading 'trim')
idValue
와 pwValue
에 문자열이 들어가는지 알 수 없어서 타입 에러가 발생했다.const idValue = watch('id') || '';
const pwValue = watch('pw') || '';
기본값으로 빈 문자열이 들어가도록 설정해주면 문제가 해결된다.
💡 이 에러를 만나고, 타입스크립트의 필요성을 느꼈다. 이 라이브러리를 이미 사용했더라면 이런 에러를 만날 일이 없지 않았을까.
이렇게까지 했는데도 여전히 빈값으로 인식한다.
1-3. register 함수
하지만 그게 아니었다. register
가 포함된 input을 useForm에서 값을 추적해 업데이트(watch
) 등 동작하는 거였다. 로그인 할 땐 유효성 검사를 거치지 않아서 에러 원인을 찾는 데 애먹었다. 😓
{...register("name", ...)}
등록2. 회원가입 유효성 에러 메시지 사라짐
하도 회원가입과 로그인 부분을 옮겨 가며 작업하다보니 어느 시점에서부터 문제가 발생한 것인지 파악하기 어려웠다. 그래서 삽질 시작.
<small>
) 안 생김 즉 동작은 하고 있으나, 화면에 표시되지 않는 문제였다. 그 이유를 못 찾다가 다른 작업 도중, 아이디/닉네임 중복 체크 버튼을 클릭하면 유효성 메시지가 확인되는 것이다!
const handleInputChange = async (fieldName, value) => {
// 값 업데이트
setValue(fieldName, value);
// 유효성 검사 실행
await trigger(fieldName);
};
...
<input
type="text"
onChange={(e) => handleInputChange('id', e.target.value)}
...
/>
리액트의 onChange 이벤트는 기본적으로 두 글자를 입력해야 한 글자를 인식한다. 즉 input의 변화에 한 발 느리게 동작한다. 유효성 검사하기엔 치명적이라서 useForm에서 제공하는 함수를 이용해 수동으로 값을 변경하기로 했다.
그래서 setValue
로 입력한 값으로 해당 필드 값을 변경하고, trigger
함수를 사용해 수동으로 유효성 검사를 실시했다.
AxiosError: Request failed with status code 400
{type(id or nickname): value}
로 요청💡 이때 type을 매개변수로 받았는데, 객체의 key를 매개변수로 받으려면 대괄호를 덧대어 준다.
const data = { [key]: value };
API 명세서가 중요하다는 걸 몸소 느꼈다. 무엇보다 Req, Res를 잘 정해두는 게 좋다고 느꼈다. 그래야 백에 넘길 데이터를 어떻게 가공할지 생각할 수 있다. 백도 마찬가지일 테고.
그러면서도 배운 게 있는데, 두 개의 input을 하나의 로직으로 처리할 땐 type으로 구분해서 전달해야 FE에서 처리하기 좋다. id와 닉네임 각각을 중복 처리하지만 사실 백에서는 처리 과정이 거의 동일하다.
그래서 엔드포인트 하나로 값만 구분하여 처리를 해줬는데, 프론트에 전달할 땐 각각 어떤 필드에 대한 처리인지 type을 전달해줘야 '중복된 아이디/닉네임입니다'를 화면에 보여주기 용이하다.
오늘은 회원가입/로그인 예외처리에 집중했다.
[회원가입]
[로그인]
case 1. key가 곧 변수일 때
setMsg((prev) => ({ ...prev, [type]: true }));
대괄호로 묶는다.
case 2. key의 일부가 변수일 때
객체 key는 따옴표 없는 문자열로 작성된다. 즉 문자열과 변수를 함께 쓰는 것과 같으므로 백틱을 사용해준다.
setMsg((prev) => ({
...prev,
[`${type}Duplicate`]: '❌',
}));
중복 체크 시 유효성 검사 여부도 확인해야 한다. 유효성 검사는 통과하지 못했는데 중복이 아니라고 간주해 잘못된 싸인을 넘길 수 있어서다.
무엇을 기준으로 유효성 검사 여부를 파악할까 고민하다가 에러 객체를 활용했다.
const handleCheck = async (type, value) => {
try {
if (errors.id) {
setMsg((prev) => ({
...prev,
[`${type}Duplicate`]: '❌',
}));
} else {
const data = { [type]: value };
const response = await axios.post(
'http://localhost:8000/member/checkDuplicate',
data
);
// 이후 요청 응답 처리
아이디, 닉네임 중복 확인을 하지 않았을 경우 회원가입 버튼이 disabled된다면 개발하는 입장에선 편하다. 추가로 예외처리할 게 없다.
하지만 유저 입장에선 유효성검사에 맞게끔 모든 값을 채웠는데도 회원가입 버튼이 활성화되지 않아 오류처럼 보일 수 있다. 그래서 유효성검사만 통과해도 회원가입 버튼은 활성화하되, 안내 메시지로 중복 확인을 유도했다.
엔터키 동작 구현에 특이점이 있었다. 바로 handleSubmit
함수에 onSubmit
함수를 매개변수로 전달한다는 점.
const handleEnter = (e) => {
if (e.key === 'Enter') {
handleSubmit(onSubmit)();
}
};
즉 handleSubmit
함수를 호출해서 새 함수를 반환한다. 그 함수(반환된 새 함수)를 호출하는 역할로 ()
이 필요한 것이다.
1️⃣ 비동기 처리할 때 useEffect
1. 발생 : 값 업데이트 될 때마다 콘솔로 확인 중인데 업데이트가 바로 안 됨
2. 원인 : state 변수는 비동기 함수이므로 업데이트 되기 전에 콘솔이 찍힐 수 있음
3. 해결 :
useEffect(() => {
console.log('signUpCk updated:', signUpCk);
console.log('msg updated:', msg);
}, [signUpCk, msg]);
useEffect로 확인하고 싶은 값이 변할 때마다 콘솔에 찍어서 원하는 대로 동작하는지 확인할 수 있었다.