자꾸 input에서 autocomplete 경고 메시지가 떴다.
autocomplete 은 자동완성이었다..!
반드시 있어야 하는 것은 아니지만, 최적의 UX와 보안을 위해 추가하는 것이 권장됨.
특히, 다음 경우에는 autocomplete 속성을 명확하게 지정하는 것이 좋아:
필수적인 경우:
• 비밀번호 필드 (autocomplete="current-password" 또는 autocomplete="new-password")
• 로그인 ID, 이메일 필드 (autocomplete="username", autocomplete="email")
불필요한 경우:
• 보안이 중요한 필드에서 자동완성을 막고 싶을 때 (autocomplete="off")
• 일반 텍스트 입력 필드에서 자동완성이 필요하지 않을 때
✅ 브라우저는 기본적으로 name 값을 기준으로 자동완성 데이터를 분류하지만,
✅ 자동완성을 적용할 때는 autocomplete 속성이 있으면 이를 우선 적용해.
name은 꼭 있어야함
폼 제출 시 (<form>
사용 시): name이 있어야 서버로 데이터를 전송할 수 있음.
브라우저 자동완성 기능: name이 있어야 브라우저가 입력 값을 저장하고 자동완성을 제공할 수 있음.
백엔드와 연동 시: API 요청에서 name 값이 필드 이름으로 사용됨.
->
<input>
요소에서 name 속성을 JSX에서 직접 지정(name={id})하면서, 동시에 register(id, ...)을 사용하고 있습니다. react-hook-form의 register 함수는 내부적으로 name을 자동으로 할당하므로, JSX에서 name을 별도로 지정하면 중복 선언 오류가 발생합니다.
해결 방법:
name={id}를 제거하면 됩니다.
✅ auto complete props에 추가하기
[ ☑️ 로직 요약 ]
유저 정보 샘플 데이터 넣어놓기
유저 정보 가져와서 기본값 보여주기
[ ☑️ 로직 디테일 ]
1. 로그인할때 유저정보도 백엔드에서 같이 가져오기
2. zustand에 저장해두기
3. 내정보 조회, 내정보 수정 - zustand에 있는 정보를 가져오기
4. 수정시 - zustand내용 수정, 백엔드 유저정보 POST(or UPDATE)로 수정
(zustand내용 수정하는 set하는 로직 안에 유저정보 POST하는 api로직도 넣어놓는것도 방법이겠군)
-> 백엔드 없이 임시 로직 구현해두려면
일단 샘플 유저데이터를 zustand에만 넣어놓으면 되겠다
✅ 내 정보 수정 페이지에 접근하면 유저의 기존 정보를 input에 default value로 보여주고싶었다.
그런데 react hook form의 default Value를 useForm에서 가져온다해도,
zustand에 있는 값을 최초로 가져온 default value가 캐시에 저장되듯 ‘최초 렌더링 시에만 반영’된다.
그래서 zustand에 있는 유저정보를 변경하더라도 zustand에 있는 업데이트된 값을 default value로 보여주는게 아니라
최초로 가져왔던 값을 그대로 보여준다.
그래서 useEffect를 사용하여 reset() 하는게 필요하다!
// Zustand에서 가져온 값으로 초기화 (내정보 수정 페이지 처음 진입 시 한 번만 실행)
useEffect(() => {
reset({ name, email, phone, companyName, });
}, [name, email, phone, companyName, reset]);
( useFormContext에서 가져오는 정확한 메서드 이름은 getValues 이다. )
getValues 사용 방법은
<input defaultValue={getValues("name")} />
☑️ zustand에서 가져온 데이터에서 그대로 input에서 수정필요
( input에 보여주고있는 기존 유저데이터를 수정하면 watch 에 감지가 안됨, submit버튼 클릭 후에야 newName이 감지되기 시작함 )
-> ✨ 해결
const { name, email, phone, companyName, isDocApproved }: UserInfo =
useUserInfoStore();
<LabelInputSet
labelText="이메일 주소"
id="email"
width="292px"
defaultValue={email}
/>
이렇게 defaultValue에 zustand에서 가져온 값을 그대로 넣어주고있었음.
-> 현재 watch("name")이 기본적으로 zustand에서 받아온 값이 아니라 react-hook-form 내부 상태만 감시하고 있어, 처음에는 값이 비어 있을 가능성이 큼.
-> defaultValue 대신 setValue를 사용하여 초기값을 강제 설정.
const { getValues, setValue, reset, watch } = useFormContext();
const newName = watch("name");
console.log("newName", newName);
// 초기값 강제 설정
useEffect(() => {
setValue("name", name);
setValue("email", email);
setValue("phone", phone);
setValue("companyName", companyName);
}, [name, email, phone, companyName, setValue]);
<LabelInputSet
labelText="이름"
id="name"
width="100%"
defaultValue={getValues("name")}
// defaultValue={name} 도 상관없음
//(초기값 보여주는것 뿐이라서 zustand값 그대로 보여줘도 됨)
/>
-> input에 기존 유저정보를 기본값으로도 보여주고,
해당 텍스트를 수정하면 watch로 바로 console창에 감지도 된다.
☑️ 제출시 수정된 내용만 zustand 수정
EditUserInfo.tsx같이 CommonForm을 사용하는 사용처에서는 getValues, setValue를 사용하지 못해 난감했다.
handleSubmit에는 methods가 필요한데, handleSubmit 함수가 있는 컴포넌트 안에서 CommonForm을 사용하고 있으니
// AccountPage.tsx
const hondleSubmit = ()=>{
// methods 필요
}
<CommonForm>
<EditUserInfo/>
</CommonForm>
CommonForm 안에 Provider, methods가 다 들어있어서
AccountPage 안에서는 getValues, setValue같은 methods를 쓸수가 없었다!!!
그럼 handleSubmit함수는 어떻게 작성하라고… ㅜㅜ
⭐️ 구조 정리
// AccountPage.tsx
<EditUserInfo/>
EditUserInfo.tsx
const methods = useForm()
<CommonForm>
<EditUserInfoContent/>
</CommonForm>
->
EditUserInfoContent.tsx
useFormContext() 사용 가능
회원가입 페이지는 SignupPage 컴포넌트를 기준으로 step1~4 컴포넌트가 동적 라우팅으로 연결되어 있다.
step1 ~ 4 모두 url 다름
하지만 입력된 정보들을 한번에 모아서 백엔드 회원가입 api에 제출할것.
방법 :
const methods = useForm()
<CommonForm methods={methods}>
<Step1>
<Step2>
…
</CommonForm>
-> useForm은 컴포넌트 언마운트, 리렌더링시 초기화됨
step1~4는 다른 url이기때문에 페이지 이동하면 CommonForm은 언마운트됨.
-> useForm에 입력된 이전 값은 초기화됨.
-> zustand로 관리 필요 (zustand값은 새로고침하지 않는 이상 리렌더링, 언마운트되어도 상태가 유지되기 때문!)
(새로고침해도 유지하고싶으면 persist와 로컬스토리지를 사용할수있다.)
api연결은 나중에 하고, 회원가입 데이터들을 한번에 제출하는게 정상 동작하는지만 handleSubmit 실행시 콘솔찍어서 제출데이터를 확인하고싶어.
추후 api연결시 handleSubmit함수에서 회원가입api에 제출하는 api 추가만 하면 되는게 맞는지?
=>
-> CommonForm을 회원가입페이지에서 감싸는데
최종제출 로직 함수는 step4에서 실행되어야함.
-> CommonForm에서 최종 실행할 함수 작성해서 onSubmit안에 넣어놓기.
step4에서는 useFormContext에서 handleSubmit을 가져와서
최종제출 클릭시 버튼에 handleSubmit을 onClick으로 추가
(원래는 handleSubmit은 콜백함수를 인자로 받는게 필수이지만,
이미 그 처리는 CommonForm에서 하고있기 때문에
step4에서는 그냥 onClick={handleSubmit}만 해도 괜찮음
근데 다른 로직도 클릭시 추가하고 싶다면 그때는
onClick={handleSubmit(() => openModal(MODAL_IDS.SIGNUP_COMPLETE))}
이런식으로 handleSubmit안에 콜백함수로 넣어주면 됨
회원가입을 이렇게 step별로 나눠서 하는걸
‘멀티 스텝 폼 Multi-Step Form’ 방식이라고 하는구나 신기하당
반대는 단일 폼 방식(One-Page Form)