我正在使用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與這個或任何其他電話號碼庫連接有什麼想法嗎?
評論中 @adsy 的提示解決了這個問題。
在元件中使用
useController
:(以及元件中
ref
的細微更改)。然後,當您呼叫它進行深度嵌套時,也解構
control
: