React-Hook-Form + Chakra-UI + beliebige Telefonnummernbibliothek (wahrscheinlich Duell-Referenzproblem)
P粉143640496
P粉143640496 2024-03-27 09:25:26
0
1
562

Ich verwende „react-hook-form“, um generische Formularkomponenten zu erstellen, die tief verschachtelt sind und über das useFormContext-Paradigma referenziert werden, um eine beliebig tiefe Verschachtelung von Komponenten zu ermöglichen. Für das Styling habe ich Chakra-UI verwendet. Das alles funktioniert gut. Allerdings möchte ich einigen Formularen die Eingabe einer internationalen Telefonnummer hinzufügen.

Es ist mir eigentlich egal, welche Bibliothek ich verwende, solange sie in einem NextJS-Kontext performant ist und mit RHF und Chakra funktioniert, daher bin ich offen für Vorschläge in eine ganz andere Richtung als unten.

Ich glaube, ich bin kurz davor, „react-international-phone“ zu verwenden.

Das Problem, das ich habe (ich hatte ähnliche, aber leicht unterschiedliche Probleme mit anderen Bibliotheken), ist, dass React-International-Phone entweder mit Chakra oder React-Hook-Form gut funktioniert, aber nicht mit beiden gleichzeitig.

Im Github-Quellcode von React-International-Phone ist ein Storybook-Beispiel in die Chakra-UI integriert, das so funktioniert:

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>
  );
};

Wenn ich nur die Chakra-Komponente Input in React-Hook-Formen verwende, würde es so aussehen:

<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>

Die beiden Probleme, die diese beiden Dinge kombinieren, sind ...register 返回 ref 到 html 输入,而 React-international-phone 需要将 onChange 作为属性传递给其 usePhoneInput Haken.

Für die erste Frage denke ich, dass ich diese Antwort verwenden und ausführen kann

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

Aber sich beschweren phoneInput.inputRef 是一个对象而不是函数。事实上,文档说它是一个 React.RefObject<HTMLInputElement> ,这......我猜不是一个函数。但后来我不确定为什么 ref={phoneInput.inputRef} funktioniert im Beispielcode.

Ich denke, ich kann das zweite Problem lösen, indem ich den React-Hook-Form-register响应并将返回的onChange传递给usePhoneInputHook umgestalte.

Zuerst habe ich das versucht

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}}
                        />

Aber das Problem ist, dass usePhoneInput ein Hook ist und daher dort eigentlich nicht aufgerufen werden kann. Mein aktueller Standort ist

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}}
                        />

Ich fühlenah genug dran, aber es funktioniert immer noch nicht. Ich habe es in CodeSandbox eingefügt. CodeSandbox ist kaputt, in App.js habe ich den Aufruf des Formulars auskommentiert, denn wenn ich den Kommentar entferne, wird mein Browser blockiert :(

Irgendwelche Ideen, wie man React-Hook-Form und Chakra-UI mit dieser oder einer anderen Telefonnummernbibliothek verbinden kann?

P粉143640496
P粉143640496

Antworte allen(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}
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage