react-hook-form + chakra-ui + 任何電話號碼庫(可能是決鬥參考問題)
P粉143640496
P粉143640496 2024-03-27 09:25:26
0
1
509

我正在使用react-hook-form來建立通用表單元件,這些元件透過useFormContext範例進行深度巢狀和引用,以實現元件的任意深度巢狀。我使用 Chakra-UI 進行造型。這一切工作正常。不過,我想在某些表單中新增國際電話號碼輸入。

我實際上並不關心我使用哪個庫,只要它在 NextJS 上下文中具有高性能並且與 RHF 和 Chakra 一起工作即可,所以我願意接受與下面完全不同的方向的建議。

我想我已經非常接近使用react-international-phone了。

我遇到的問題(我在其他函式庫中也遇到類似但略有不同的問題)是react-international-phone 與Chakra 或react-hook-form 配合良好,但不能同時與兩者配合使用同時。

在 Github 原始碼中,react-international-phone 有一個與 Chakra-UI 整合的 Storybook 範例,其工作原理如下:

export const ChakraPhone = ({
  value,
  onChange,
}) => {
  const phoneInput = usePhoneInput({
    defaultCountry: 'us',
    value,
    onChange: (data) => {
      onChange(data.phone);
    },
  });

  return (
    <ChakraProvider>
        <Input
          value={phoneInput.phone}
          onChange={phoneInput.handlePhoneValueChange}
          ref={phoneInput.inputRef}
        />
    </ChakraProvider>
  );
};

如果我只是在react-hook-forms中使用Chakra Input元件,它看起來會像這樣:

<ConnectForm>
    {({ formState: { errors }, register}) => (
        <form>
            <FormControl isInvalid={errors.phone}>
                <FormLabel htmlFor='phone'>Phone Number</FormLabel>
                <Input
                  id='phone'
                  name='phone'
                  {...register('phone')} />
            </FormControl>
        </form>
    )}
</ConnectForm>

將這兩件事結合起來的兩個問題是...register 回傳ref 到html 輸入,而React-international-phone 需要將onChange 作為屬性傳遞給其usePhoneInput 掛鉤。

對於第一個問題,我想我可以使用這個答案並執行

<Input
    value={phoneInput.phone}
    onChange={phoneInput.handlePhoneValueChange}
    name={name}
    ref={(el) => {reactHookRef(el); phoneInput.inputRef(el)}}
/>

但是抱怨 phoneInput.inputRef 是一個物件而不是函數。事實上,文檔說它是一個 React.RefObject<HTMLInputElement> ,這......我猜不是一個函數。但後來我不確定為什麼 ref={phoneInput.inputRef} 在範例程式碼中起作用。

我認為我可以透過重構react-hook-form register回應並將返回的onChange傳遞給usePhoneInput鉤子來解決第二個問題。

最初我嘗試這樣做

const PhoneNumberInput = (props) => {
    return (    
        <ConnectForm>
            {({ formState: { errors }, register }) => {
                const { onChange, onBlur, name, ref: reactHookRef } = register('phone');
                const phoneInput = usePhoneInput({
                    defaultCountry: 'gb',
                    onChange: onChange
                })

                return (    
                    <ConnectForm>
                        <Input
                            type='tel'
                            value={phoneInput.phone}
                            onChange={phoneInput.handlePhoneValueChange}
                            name={name}
                            ref={(el) => {reactHookRef(el); phoneInput.inputRef}}
                        />

但問題是 usePhoneInput 是一個鉤子,所以實際上不能在那裡呼叫它。我現在所在的位置是

const PhoneNumberInput = (props) => {
    const [ onChangeRHF, setOnChangeRHF ] = useState();

    const phoneInput = usePhoneInput({
        defaultCountry: 'gb',
        onChange: onChangeRHF
    })

    return (    
        <ConnectForm>
            {({ formState: { errors }, register }) => {
                const { onChange, onBlur, name, ref: reactHookRef } = register('phone');
                setOnChangeRHF(onChange);

                return (
                    <>
                        <InputGroup size={props?.size} id={props?.id || 'phone'}>
                            <InputLeftAddon width='4rem'>
                                <CountrySelector
                                    selectedCountry={phoneInput.country}
                                    onSelect={(country) => phoneInput.setCountry(country.iso2)}
                                    renderButtonWrapper={({ children, rootProps }) => 
                                        <Button {...rootProps} variant={'outline'} px={'4px'} mr={'8px'}>
                                            {children}
                                        </Button>
                                    }
                                />
                            </InputLeftAddon>
                        <Input
                            type='tel'
                            value={phoneInput.phone}
                            onChange={phoneInput.handlePhoneValueChange}
                            onBlur={onBlur}
                            name={name}
                            ref={(el) => {reactHookRef(el); phoneInput.inputRef}}
                        />

感覺已經很接近了,但它仍然不起作用。我已將其放入 CodeSandbox 中。 CodeSandbox 已損壞,在 App.js 中,我註解掉了對表單的調用,因為如果我取消註釋,它會鎖定我的瀏覽器:(

關於如何將react-hook-form和chakra-ui與這個或任何其他電話號碼庫連接有什麼想法嗎?

P粉143640496
P粉143640496

全部回覆(1)
P粉680487967

評論中 @adsy 的提示解決了這個問題。

在元件中使用useController

const PhoneNumberInput = ({ control, name, size='md' }) => {
    const {
        field,
        fieldState: { invalid, isTouched, isDirty },
        formState: { touchedFields, dirtyFields }
    } = useController({
        name,
        control
    })

    const phoneInput = usePhoneInput({
        defaultCountry: 'gb',
        onChange: (data) => {
            field.onChange(data.phone);
        }
    })

    return (
        
            
                
                     phoneInput.setCountry(country.iso2)}
                        renderButtonWrapper={({ children, rootProps }) => 
                            
                        }
                    />
                
                 field.ref(el) && phoneInput.inputRef}
                />
            
        >
    )
};

export default PhoneNumberInput;

(以及元件中 ref 的細微更改)。

然後,當您呼叫它進行深度嵌套時,也解構 control


        {({ control, formState: { errors }, register}) => (
            
Phone Number {errors.phone && errors.phone.message}
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板