Closed jinyoung234 closed 1 year ago
https://react-hook-form.com/api/useformcontext
저는 한 프로젝트에서 Input component에 methods를 내려줄 때 위의 form context방식을 적용했습니다.
@jinyoung234
function SignUpForm({
form: {handleSubmit, onValid},
input: {register},
}: SignUpProps) {
return (
<>
~구조분해 할당을 잘못 하신거 아닐까요?~
function SignUpForm(props) {
~이 형태로 받고 props로 들어오는 값을 보시면 될거 같습니다~
아 이 문제는 아니겠군요 (취소)
console.log(rest)는 잘 찍히고 있나요?
import React from 'react'
import {UseFormRegister} from 'react-hook-form'
import {IFormData} from '../../auth/SignUpForm/type'
import {InputProps} from './type'
const Input = React.forwardRef<HTMLInputElement, InputProps & ReturnType<UseFormRegister<IFormData>>>(
({...rest}: InputProps, ref) => {
return (
<>
<input ref={ref} {...rest} />
</>
)
},
)
Input.displayName = 'input'
export default Input
공식문서 보면서 forwardRef로 바꾸니까 해결은 됬는데 정확한 원인은 잘 모르겠어서 좀 더 공부해봐야할 거 같습니다.. ㅜㅜ 혹시 괜찮으시다면 같이 고민해보면 좋을 거 같긴 한데 다른 분들 사정도 있으시니..! 일단 rest 찍히는지도 확인해보겠습니다!
@jinyoung234 아하 forwardRef 문제가 맞을거 같아요 결국 react-hook-form 쪽에 해당 input에 대한 ref 값을 넘겨야 하는데 forwardRef로 넘기지 않으면 ref가 넘어가지 않기 때문에 useForm 입장에서는 입력받은 ref가 없는 상황일 것 같네요
아 Input의 ref를 useForm에 넘겨주는 원리여서 forwardRef를 통해 넘겨주는 걸로 이해해도 될까여?!
https://react-hook-form.com/api/useform/register/
보시면 register의 리턴값 중에 ref도 있는데요 Form.Input에 register 함수만 넘기시고, Input 안쪽에서 {...register(foo)} 하게 되면 forwardRef 없이도 될것 같은 느낌적인 느낌이네요 @jinyoung234
그렇게 할 수 있으면 좋을거 같은데 input이 공통 컴포넌트라 id에도 쓰고 pw에도 사용하는데도 가능할까여 혹시..?!
그리고 한가지 더 여쭤보고 싶은게 있는데 지금 제가 컨테이너 - 프레젠터 패턴을 염두에 잡고 위 코드 대로 진행을 했습니다. 보시면 SignUpForm에서 Input으로 register를 한번 더 내려주게 되어 정확한 비즈니스 - 뷰 분리가 안된거 같아서 그런데 혹시 SignUpForm을 컨테이너 - 프레젠터로 한번 더 나눠야 할까요..?!ㅜㅜ 답변 힘드시면 괜찮습니다!
2) 아래와 같이 처리할 수는 없나요?
function SignUpForm({
form: {handleSubmit, onValid},
input: {register},
}: SignUpProps) {
return (
<>
<Form handleSubmit={handleSubmit(onValid)}>
<Form.Input type='text' id='id' register={register('id')} />
<Form.Input type='password' id='pw' register={register('pw')} />
</Form>
</>
)
}
function Input({id, type, register, ...rest}: InputProps) {
return <input {...rest} {...register} />
}
아 타입을 그렇게 설정할 수도 있군여..! 수정해보겠습니다. 제가 생각한 프레젠터는 완전 뷰와 관련된 로직만 포함시키는게 목적이었어서 이 설계가 잘못된 설계라고 생각했는데, 혹시 제가 해당 패턴을 잘못 이해한건지 알고 싶습니다 ㅜㅜ!
props의 타입과 관련된 이슈라면, react-hook-form에서 제공하는 FormProvider 사용해보시는 것도 좋을거 같아요,
FormProvider
로 감싼 context 내에서 useForm의 method들을 공유할 수 있어서 props로 register를 전달하는 방법보다 괜찮지 않을까 생각합니다.
@LucetTin5 님과 같은 맥락이네요
@LucetTin5 @zeromountain 감사합니다 참고하겠습니다!
답변이 매우 늦었지만 이전 프로젝트에서 정확히 같은 문제로 고생했어서 답변 남깁니다..! 멘토님 답변처럼 register 리턴에 ref가 있는게 문제더라구요.. 저는 폼타입을 제네릭으로 받아서 register를 통으로 받아 해결했었습니다..!
interface InputProp<T extends FieldValues> extends InputHTMLAttributes<HTMLInputElement> {
label?: string | undefined;
plHolder?: string | undefined;
name: FieldPath<T>;
register: UseFormRegister<T>;
options?: RegisterOptions<T, FieldPath<T>>;
};
function Input<T extends FieldValues>({
label,
plHolder,
name,
type = 'text',
required,
register,
options,
}: InputProp<T>) {
return (
<S.Input className="input-container">
<label>
{label && <div className="label">{label}</div>}
<input
{...register(name, options)}
placeholder={plHolder}
required={required}
autoComplete="off"
type={type}
/>
</label>
</S.Input>
);
}
@young-st511 오 감사합니다 참고하겠습니다..!!
질문
안녕하세요..! 리팩토링을 진행하다가 react-hook-form에 있는 input을 건들고 있는데, 다음과 같이 register 함수를 프레젠터에 내려주어 내려받은 함수를 Input에 다시 내려주는 형태입니다. 하지만 컨테이너에서 콘솔로 watch 함수로 호출하여 보니 id, pw가 undefined로 찍히게 됩니다. 원인을 알 수 없어 질문 남기게 되었습니다!
비즈니스 로직을 내려주는 컨테이너 컴포넌트 입니다.
컨테이너에서 데이터를 내려 받아 사용하는 SignUpForm 컴포넌트(presenter) 입니다.
register에 있는 attribute들과, id, type prop을 받는 Input 컴포넌트 입니다.