我正在使用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与这个或任何其他电话号码库连接有什么想法吗?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
评论中 @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: