1️⃣첫번째 버그
0. 버그 현황
- 아이디 input 값에 이미 사용중인 아이디를 입력하고 중복확인 버튼을 클릭했을 때 이미 사용중인 아이디입니다. 라고
에러메세지가 정상적으로 렌더링 된다.
- input 값을 수정해서 또 이미 사용중인 아이디를 입력하고 중복확인 버튼을 클릭했을때는 에러메세지가 렌더링이 되지 않음
1. 버그 코드
- 기존에는 useEffect 를 써서 errorMsg 상태값이 변할 때마다 에러메세지를 렌더링 하는 코드로 짰었음
function JoinForm() {
const [toggleType, setToggleType] = useState("buyer");
const [isJoinValid, setIsJoinValid] = useState(false);
const [idChecked, setIdChecked] = useState(false);
const [businessChecked, setBusinessChecked] = useState(false);
const {
register,
handleSubmit,
getValues,
setError,
watch,
trigger,
formState: { errors },
} = useForm({ mode: "onChange" });
const dispatch = useAppDispatch();
const errorMsg = useAppSelector((state) => state.join.error);
const successMsg = useAppSelector((state) => state.join.successMsg);
// id 중복 확인 검증
const handleCheckId = async (
id: string,
e: React.MouseEvent<HTMLButtonElement>
) => {
e.preventDefault();
const isValid = await trigger("id");
if (!isValid) {
return;
}
const resultAction = await dispatch(fetchIdValidate(id));
if (fetchIdValidate.fulfilled.match(resultAction)) {
setIdChecked(true);
}
};
// id 중복 확인 & 사업자 등록 번호 검증 에러메세지
useEffect(() => {
if (errorMsg === "username 필드를 추가해주세요 :)") {
setError("id", {
message: errorMsg,
});
} else if (errorMsg === "이미 사용 중인 아이디입니다.") {
setError("id", {
message: errorMsg,
});
} else if (
errorMsg === "company_registration_number 필드를 추가해주세요 :)"
) {
setError("businessNo", {
message: errorMsg,
});
} else if (errorMsg === "이미 등록된 사업자등록번호입니다.") {
setError("businessNo", {
message: errorMsg,
});
}
}, [errorMsg, setError]);
// ... 중략
return (
<>
<ToggleBtn toggleType={toggleType} setToggleType={setToggleType} />
<form onSubmit={handleSubmit(onSubmit)}>
<S.JoinSection>
<JoinInput
label="아이디"
forid="id"
type="text"
width={346}
isButton={true}
onClick={(e) => handleCheckId(getValues("id"), e)}
{...register("id", {
required: "필수 정보입니다.",
pattern: {
value: regExp.ID_REGEX,
message:
"20자 이내의 영문,소문자, 대문자, 숫자만 사용 가능합니다.",
},
onChange: () => {
if (idChecked) {
setIdChecked(false);
}
},
})}
/>
{idChecked ? (
<S.SuccessTxt>{successMsg.Success}</S.SuccessTxt>
) : (
RenderErrorMsg(errors.id)
)}
// ... 중략
</S.JoinSection>
<CheckTerm
register={register("checkbox")}
children="호두샵의 이용약관 및 개인정보처리방침에 대해 동의합니다"
/>
<S.JoinBtn type="submit" size="md" disabled={!isJoinValid}>
가입하기
</S.JoinBtn>
</form>
</>
);
}
export { JoinForm };
2. 해결 코드
- 에러메세지를 렌더링 하는 코드를 useEffect 로 따로 감싸지 말고, 버튼을 클릭할때마다 즉,
handleCheckId 를 클릭할 때마다 에러메세지가 렌더링 하게 해준다.
// id 중복 확인 검증
const handleCheckId = async (
id: string,
e: React.MouseEvent<HTMLButtonElement>
) => {
e.preventDefault();
const isValid = await trigger("id");
if (!isValid) {
return;
}
const resultAction = await dispatch(fetchIdValidate(id));
if (fetchIdValidate.fulfilled.match(resultAction)) {
setIdChecked(true);
} else if (errorMsg === "이미 사용 중인 아이디입니다.") {
setError("id", {
message: errorMsg,
});
}
};
// 사업자등록 번호 인증
const handleCheckBusiness = async (
businessNo: string,
e: React.MouseEvent<HTMLButtonElement>
) => {
e.preventDefault();
const isValid = await trigger("businessNo");
if (!isValid) {
return;
}
const resultAction = await dispatch(fetchBusinessValidate(businessNo));
if (fetchBusinessValidate.fulfilled.match(resultAction)) {
setBusinessChecked(true);
}
};
// id 중복 확인 & 사업자 등록 번호 검증 에러메세지
useEffect(() => {
if (errorMsg === "company_registration_number 필드를 추가해주세요 :)") {
setError("businessNo", {
message: errorMsg,
});
} else if (errorMsg === "이미 등록된 사업자등록번호입니다.") {
setError("businessNo", {
message: errorMsg,
});
}
}, [errorMsg, setError]);
2️⃣두번째 버그
0. 버그 현황
- 첫번째 버그에서 버튼을 클릭할때마다 에러메세지가 렌더링 하는걸로 바꾸었는데,
이번에는 중복확인 버튼을 2번 클릭해야지만 에러메세지가 렌더링 되는걸로 바뀌었다.
홈페이지 새로고침하고 처음 중복확인 버튼을 바로 눌렀을때는 에러메세지가 렌더링 되지않는 문제가 생겼다.
- 더욱 웃긴것은 글자만 렌더링 되지 않고, input 창 밑에 small 태그가 새로 생기는 현상이 있었다.
1. 버그 코드
2. 해결 코드
- 기본값을 설정해야하는 이유는?
코드를 살펴보면, errorMsg는 useAppSelector((state) => state.join.error)를 통해 Redux 상태에서 가져온 값이다.
handleCheckId 함수에서 fetchIdValidate 액션을 디스패치한 후, 반환된 resultAction에 따라 에러 메시지를 설정합니다.
그러나 경우에 따라 errorMsg 값이 아직 업데이트되지 않은 상태일 수 있다. 따라서 setError 함수를 호출할 때 errorMsg가 undefined이거나 빈 문자열이라면 기본값으로 "이미 사용 중인 아이디입니다."를 사용해야한다. 이렇게 하면, errorMsg가 올바르게 설정되지 않은 경우에도 사용자에게 에러 메시지를 표시할 수 있다.
errorMsg || "이미 사용 중인 아이디입니다."는 JavaScript의 논리 연산자인 ||를 사용하여 두 값 중 "참"으로 평가되는 첫 번째 값을 반환합니다. errorMsg가 존재하고 유효한 값이라면 그대로 사용되고, 그렇지 않으면 기본 메시지인 "이미 사용 중인 아이디입니다."가 사용된다. 이렇게 작성하면 예상치 못한 상황에서도 에러메세지가 렌더링 되도록 보장할 수 있다.
- errorMsg 값이 업데이트 되지 않은 상태일땐 언제일까?
setError 호출 시점에 errorMsg 상태가 아직 업데이트되지 않았기 때문일 수 있습니다. 상태 업데이트는 비동기적으로 처리되기 때문에 이러한 현상이 발생할 수 있습니다.
errorMsg 값이 아직 업데이트되지 않은 상태는, Redux 상태가 변경되기 전에 setError 함수가 호출되는 경우이다.
이러한 상황은 다음과 같은 원인으로 발생할 수 있다.
1) 비동기 작업: handleCheckId 함수에서 fetchIdValidate 액션을 디스패치하고, 그 결과를 기다린 후에 에러 메시지를 설정하는 과정이 비동기적으로 진행된다. 따라서, 액션을 디스패치한 후 Redux 상태가 즉시 업데이트되지 않을 수 있습니다.
2) 컴포넌트 렌더링 순서: React는 가상 DOM을 사용하여 컴포넌트를 렌더링합니다. Redux 상태가 변경되면 해당 변경 사항을 가상 DOM에 반영한 후, 실제 DOM에 렌더링합니다. 이 과정에서 컴포넌트가 다시 렌더링되기 전에 setError 함수가 호출될 수 있다.
이러한 이유로 인해 errorMsg 값이 아직 업데이트되지 않은 상태에서 setError 함수가 호출될 수 있습니다. 이 때 기본 메시지를 사용하면 예상치 못한 상황에서도 에러 메시지가 렌더링 되도록 보장받을 수 있다.
- 그런데 console 창에 console.log(errorMsg) 를 표시해보면 이미 사용중인 아이디입니다. 라고 메세지가 뜨는데 왜 렌더링은 안될까?
console.log(errorMsg)가 "이미 사용 중인 아이디입니다."라는 메시지를 표시한다면, errorMsg 값이 업데이트된 상태이다. 그러나 이 메시지가 렌더링되지 않는 이유는 setError 함수가 호출되는 시점과 React 컴포넌트 렌더링 사이의 타이밍 차이 때문일 수 있다.
setError 함수가 호출되면, 에러 메시지가 errors 객체에 저장됩니다. 그러나 React는 상태 변경을 감지한 후에 즉시 컴포넌트를 다시 렌더링하지 않을 수 있습니다. 대신, 여러 상태 변경을 한 번에 묶어서 처리하거나, 성능 최적화를 위해 렌더링을 지연시킬 수 있습니다.
이러한 이유로 인해, console.log(errorMsg)가 메시지를 표시하는 시점과 실제로 컴포넌트가 다시 렌더링되는 시점 사이에 차이가 발생할 수 있습니다. 이 차이 때문에 에러 메시지가 즉시 렌더링되지 않을 수 있습니다.
'프로젝트 이모저모 > HoduMarket 프로젝트' 카테고리의 다른 글
오픈마켓) 라이트하우스 성능점수 13점 -> 67점으로 3배 껑충 (0) | 2023.04.17 |
---|---|
오픈마켓) 자동,페이지네이션 캐러셀 슬라이드 만들기 (feat. 리액트/타입스크립트) (0) | 2023.04.17 |
오픈마켓) 로그인 폼 navigate 이동 안되는 이슈(렌더링/클로저트랩/useEffect) (0) | 2023.04.12 |
오픈마켓) 회원가입 에러메세지 - react-hook-form 버그 (0) | 2023.04.07 |
리액트+타입스크립트) styled-components theme 설정하기 (0) | 2023.03.14 |