recherche

Maison  >  Questions et réponses  >  le corps du texte

réagir-hook-form + chakra-ui + n'importe quelle bibliothèque de numéros de téléphone (probablement un problème de référence de duel)

J'utilise React-hook-form pour créer des composants de formulaire génériques profondément imbriqués et référencés via le paradigme useFormContext afin de permettre une imbrication arbitrairement profonde des composants. J'ai utilisé Chakra-UI pour le style. Tout cela fonctionne bien. Cependant, je voudrais ajouter un numéro de téléphone international à certains formulaires.

Je ne me soucie pas vraiment de la bibliothèque que j'utilise tant qu'elle est performante dans un contexte NextJS et fonctionne avec RHF et Chakra, je suis donc ouvert aux suggestions dans une direction complètement différente de celle ci-dessous.

Je pense que je suis sur le point d'utiliser React-International-Phone.

Le problème que j'ai (j'ai eu des problèmes similaires mais légèrement différents avec d'autres bibliothèques) est que React-International-Phone fonctionne bien avec Chakra ou React-Hook-Form, mais pas les deux en même temps.

Dans le code source de Github, React-international-phone a un exemple Storybook intégré à Chakra-UI qui fonctionne comme ceci :

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

Si j'utilise simplement le composant Chakra Input dans les formes de crochet de réaction, cela ressemblerait à ceci :

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

Les deux problèmes qui combinent ces deux choses sont ...register 返回 ref 到 html 输入,而 React-international-phone 需要将 onChange 作为属性传递给其 usePhoneInputles crochets.

Pour la première question, je pense que je peux utiliser cette réponse et exécuter

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

Mais se plaindre phoneInput.inputRef 是一个对象而不是函数。事实上,文档说它是一个 React.RefObject<HTMLInputElement> ,这......我猜不是一个函数。但后来我不确定为什么 ref={phoneInput.inputRef} fonctionne dans l'exemple de code.

Je pense que je peux résoudre le deuxième problème en refactorisant le formulaire de réaction-hook-form register响应并将返回的onChange传递给usePhoneInputhook.

Au départ, j'ai essayé ça

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

Mais le problème est que usePhoneInput est un crochet, donc on ne peut pas réellement l'appeler ici. Ma position actuelle est

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

Je me sensassez proche mais ça ne marche toujours pas. Je l'ai mis dans CodeSandbox. CodeSandbox est cassé, dans App.js j'ai commenté l'appel au formulaire car si je le décommente, cela bloque mon navigateur :(

Des idées sur la façon de connecter React-Hook-Form et Chakra-UI avec ceci ou toute autre bibliothèque de numéros de téléphone ?

P粉143640496P粉143640496232 Il y a quelques jours500

répondre à tous(1)je répondrai

  • P粉680487967

    P粉6804879672024-03-28 00:17:15

    Le conseil de @adsy dans les commentaires a résolu le problème.

    Utiliser useController dans un composant :

    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;

    (et modifications mineures de ref dans les composants).

    Puis quand vous l'appelez pour une imbrication profonde, déstructurez également control :

    
            {({ control, formState: { errors }, register}) => (
                
    Phone Number {errors.phone && errors.phone.message}

    répondre
    0
  • Annulerrépondre