(React Native) Can this package be used in the React Native?
irsyaadbp opened this issue · 70 comments
Can this package be used in the react native
Update: Yes, "without country select" component.
First, create PhoneTextInput.js
file:
import React, { useCallback } from 'react'
import PropTypes from 'prop-types'
import { TextInput } from 'react-native'
function PhoneTextInput({
placeholder,
autoComplete,
autoFocus,
value,
onChange
}, ref) {
// Instead of `onChangeText` it could use `onChange` and get `value` from `nativeEvent.text`.
const onChangeText = useCallback((value) => {
onChange({
preventDefault() { this.defaultPrevented = true },
target: { value }
})
}, [onChange])
return (
<TextInput
ref={ref}
placeholder={placeholder}
autoFocus={autoFocus}
autoCompleteType={autoComplete}
keyboardType="phone-pad"
onChangeText={onChangeText}
value={value}/>
)
}
PhoneTextInput = React.forwardRef(PhoneTextInput)
PhoneTextInput.propTypes = {
placeholder: PropTypes.string,
autoComplete: PropTypes.string,
autoFocus: PropTypes.bool,
value: PropTypes.string,
onChange: PropTypes.func.isRequired
}
export default PhoneTextInput
Then, in a React Native application:
import React, { useState } from 'react'
import PhoneInput from 'react-phone-number-input/input'
import PhoneTextInput from './PhoneTextInput'
function Example() {
const [value, setValue] = useState()
return (
<PhoneInput
style={...}
smartCaret={false}
inputComponent={PhoneTextInput}
defaultCountry="US"
value={value}
onChange={setValue} />
)
}
Report in this issue if it works.
Also see the previous question: #283 (comment)
@catamphetamine "without country select" doesn't work with react native. Although I am trying out a simple example with text input and the libphonenumber-js to work out something. Till now what I have done has worked till some extent but it will be great if you could help me in understanding how the smart caret works in your react component. For now the caret has a jumping effect when it meets with a blank space or a bracket.
"without country select" doesn't work with react native.
How are you using it?
Is it v3?
Till now what I have done has worked till some extent but it will be great if you could help me in understanding how the smart caret works in your react component. For now the caret has a jumping effect when it meets with a blank space or a bracket.
Smart caret is using input-format
library.
How are you using it?
I am using it as per the instructions in the readme for using "without country select"
Is it v3?
Yes, the latest. 3.0.13.
Smart caret is using
input-format
library.
Any suggestions on how to use with react native input or how you implement it with react input?
I am using it as per the instructions in the readme for using "without country select"
Then it won't work because React Native most likely doesn't support <select/>
.
https://github.com/catamphetamine/react-phone-number-input/blob/master/source/PhoneInput.js
See if inputComponent={Select}
fixes the issue.
Any suggestions on how to use with react native input or how you implement it with react input?
See the InputSmart.js
file of this library if you want to copy the behavior.
Then it won't work because React Native most likely doesn't support
<select/>
Yes you are correct.
See if
inputComponent={Select}
fixes the issue
You mean to pass in the react native TextInput component here?
You mean to pass in the react native TextInput component here?
Yes.
Maybe something like:
import React from 'react'
import { TextInput } from 'react-native'
export default function PhoneTextInput({
placeholder,
autoComplete,
autoFocus,
value,
onChange
}) {
return (
<TextInput
placeholder={placeholder}
autoFocus={autoFocus}
autoCompleteType={autoComplete}
keyboardType="phone-pad"
onChangeText={onChange}
value={value}
/>
);
}
Report if it works.
Ok, copying the above as a separate component and calling it as following:
<PhoneInput
country="IN"
inputComponent={ PhoneTextInput } // <= From your example component above
value={this.state.mobile_number}
onChange={ this._phoneInputHandler }
/>
Let me know if my interpretation is correct.
Yes, see if it works.
I don't have React Native so I didn't check.
@catamphetamine On Load I get a warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
On typing in the first digit, I also get an error: TypeError: Undefined is not an object(evaluating 'input.value')
On Load I get a warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef().
The component uses React.forwardRef()
.
I added ref={...}
on demo page to "without country select" and it didn't print any warning.
On typing in the first digit, I also get an error:
input.value
is being accessed from input-format
package.
input
is the ref
.
ref
isn't working in your case for some reason, so input
is undefined
in input-format
package.
Actually, we didn't forward ref in <PhoneTextInput/>
.
See if this works:
import React from 'react'
import PropTypes from 'prop-types'
import { TextInput } from 'react-native'
function PhoneTextInput({
placeholder,
autoComplete,
autoFocus,
value,
onChange
}, ref) {
return (
<TextInput
ref={ref}
placeholder={placeholder}
autoFocus={autoFocus}
autoCompleteType={autoComplete}
keyboardType="phone-pad"
onChangeText={onChange}
value={value}
/>
)
}
PhoneTextInput = React.forwardRef(PhoneTextInput)
PhoneTextInput.propTypes = {
placeholder: PropTypes.string,
autoComplete: PropTypes.string,
autoFocus: PropTypes.bool,
value: PropTypes.string,
onChange: PropTypes.func.isRequired
}
export default PhoneTextInput
input.value is being accessed from input-format package.
Do I need to install the input-format
package separately?? Since I still get the error: TypeError: Undefined is not an object(evaluating 'input.value')
. Although the warning is gone.
Do I need to install the input-format package separately?
No, it's installed automatically.
The code above should work because it forwards ref
now.
Did the forwardRef
warning disappear?
Yes, the forward ref warning disappeared but I get the TypeError
.
So, the error originates at that function:
https://github.com/catamphetamine/input-format/blob/26abb77bec3ac5984f7fe99408846464fda6136a/source/input%20control.js#L35-L38
Called from here:
https://github.com/catamphetamine/input-format/blob/26abb77bec3ac5984f7fe99408846464fda6136a/source/react/Input.js#L35-L41
And input
there is ref.current
.
There, for some reason ref.current
is undefined
.
I read a bit about React Native, and found out that even if the input
wasn't undefined
, still there's no input.value
property, so I guess input-format
won't work in React Native.
The alternative then is passing smartCaret={false}
property when creating a <PhoneInput/>
"without country select" component element.
react-phone-number-input/source/PhoneInput.js
Line 103 in d84e5ad
So, see if such code works:
import PhoneInput from 'react-phone-number-input/input`
<PhoneInput smartCaret={false} .../>
On adding smartCaret: { false }
I receive a TypeError
on keying in numbers.
This is what I have currently:
<PhoneInput
style={ styles.phoneNumberInput }
smartCaret={ false }
country="IN"
inputComponent={ PhoneTextInput }
value={ this.state.mobile_number }
onChange={ (number) => this._phoneInputHandler(number) }
/>
So event.target.value
is undefined
at this line of code:
You can add some kind of
console.log(event.target.value)
in onChange
to see what's the value
there.
<PhoneTextInput onChange={event => { console.log(event); onChange(event); }}/>
The log turns out to be huge! So I am pasting the nativeEvent
right after I typed a single digit 9:
"nativeEvent": {"eventCount": 1, "target": 43, "text": "9"}, "target": 43, "timeStamp": 1579864644085, "type": undefined}
Huh, so target
is a number in React Native?
How does one get value then.
Well, ok, then try this instead:
<PhoneTextInput onTextChange={value => onChange({
preventDefault() { this.defaultPrevented = true },
target: { value }
})}/>
It creates an event
stub from a value
.
Perhaps there're more correct ways.
I guess we get the values from nativeEvent.text
.
<PhoneTextInput onTextChange={value => onChange({ preventDefault() { this.defaultPrevented = true }, target: { value } })}/>
Where should I try the above?
I guess we get the values from
nativeEvent.text
.
Maybe. That could be a second route. Not yet though.
Where should I try the above?
I meant:
<TextInput onTextChange={(value) => onChange({
preventDefault() { this.defaultPrevented = true },
target: { value }
})}/>
My current implementation was as following:
<PhoneInput
style={ styles.phoneNumberInput }
smartCaret={ false }
country="IN"
inputComponent={ PhoneTextInput }
value={ this.state.mobile_number }
onChange={ (number) => this._phoneInputHandler(number) }
/>
where PhoneTextInput is:
function PhoneTextInput({
placeholder,
autoComplete,
autoFocus,
value,
onChange,
style,
}, ref) {
return (
<TextInput
style={ style }
ref={ ref }
placeholder={ placeholder }
autoFocus={ autoFocus }
autoCompleteType={ autoComplete }
keyboardType="phone-pad"
onChange={ event => { console.log(event); onChange(event); } }
value={ value }
onTextChange={value => onChange({
preventDefault() {
this.defaultPrevented = true
},
target: {value}
})}
/>
);
}
PhonePadInput = React.forwardRef(PhoneTextInput);
I am not sure if this is the way you mean.
On a side note, I have been trying out to implement this on my own without react-phone-number-input
library and using only libphonenumber-js
. I have been able to get the formatting done on the fly but one issue arises and that is on erasing a phone number entered. The issue is similar to this: catamphetamine/libphonenumber-js#225. If you would like to know how I am doing it, I would love to paste it in here.
Remove onChange={ event => { console.log(event); onChange(event); } }
because it's now replaced with onChangeText
.
If you would like to know how I am doing it, I would love to paste it in here.
I won't assist with any custom components, only with parts of react-phone-number-input
.
Remove
onChange={ event => { console.log(event); onChange(event); } }
because it's now replaced with onChangeText.
function PhoneTextInput({
placeholder,
autoComplete,
autoFocus,
value,
onChange,
style,
}, ref) {
return (
<TextInput
style={ style }
ref={ ref }
placeholder={ placeholder }
autoFocus={ autoFocus }
autoCompleteType={ autoComplete }
keyboardType="phone-pad"
value={ value }
onTextChange={value => onChange({
preventDefault() {
this.defaultPrevented = true
},
target: {value}
})}
/>
);
}
PhoneTextInput = React.forwardRef(PhoneTextInput);
and then in the main screen I am calling it as follows:
_phoneInputHandler = (value) => {
this.setState({ mobile_number: value });
};
<PhoneInput
style={ styles.phoneNumberInput }
smartCaret={ false }
country="IN"
inputComponent={ PhonePadInput }
value={ this.state.mobile_number }
onChange={ (number) => this._phoneInputHandler(number) }
/>
With the above in place, when I key in a number, it comes and then disappears.
What does console.log
say?
_phoneInputHandler = (value) => {
console.log(value)
this.setState({ mobile_number: value });
};
It has nothing.
I won't assist with any custom components, only with parts of
react-phone-number-input
Its completely fine. Actually I was hoping for some guidance on the way you took to solve that issue in your react-phone-number-input
package.
It has nothing.
What do you mean.
What is the value
there.
Actually I was hoping for some guidance on the way you took to solve that issue in your
react-phone-number-input
package.
If there're caret issues when clearing the number then see InputBasic.js
's onChange
function fix.
What is the
value
there.
Nothing gets logged.
Nothing gets logged.
Nothing gets logged when you input a digit?
Exactly. Nothing gets logged when I input a digit.
Exactly. Nothing gets logged when I input a digit.
Then it's not working.
See what does it output in onTextChange
.
onTextChange={value => {
console.log('onTextChange', value)
onChange({
preventDefault() {
this.defaultPrevented = true
},
target: {value}
})
}
Still nothing gets logged.
Still nothing gets logged.
Hmm, that would mean React Native's <TextInput/>
onTextChange
isn't working, which is unlikely.
You could also try something else, like replacing onTextChange
with onChange(event)
and then event.nativeEvent.text
.
Exactly. Nothing gets logged when I input a digit.
I looked at the source code again and turns out that instead of onTextChange
property name it should have been onChangeText
property name.
If you still have the code, see if it works with onTextChange
property renamed to onChangeText
property.
@catamphetamine for now, I don't have the code as this part was delaying my progress with my app. But as far as I remember I did spot his mistake and tried with onChangeText
but it didn't work out.
BTW, just a thought, why don't you publish a new package for RN? It would be just great! ;)
But as far as I remember I did spot his mistake and tried with
onChangeText
but it didn't work out.
I see.
Ok.
BTW, just a thought, why don't you publish a new package for RN?
Because I haven't worked with React Native, and so I'm not a specialist in it, and developing a React Native version of this package would better be done by someone being an expert in React Native.
I don't even have it on my PC.
That's why I didn't test the code myself.
Don't have time for everything in this world )
so I'm not a specialist in it
Neither am I. :(
Don't have time for everything in this world
True for everyone. :)
Not sure if I have the time for this, but I'll take a look, as I might need to use this in my RN project. @catamphetamine This would require me refactoring the styles to get rid of CSS to make it work in RN. Should I just fork into a separate library?
This would require me refactoring the styles to get rid of CSS to make it work in RN. Should I just fork into a separate library?
I've posted the theoretically supposedly working React Native "without country select" component in the first comment in this issue.
See if it works.
It doesn't imply any styles, so no things to "get rid of".
Hey @catamphetamine, I can confirm that the snippets in your first comment work on React Native. I implemented my own country selector dropdown to go along with it using react-native-picker-select and it works great.
I couldn't figure out how to replicate the behaviour in the "Force international format" example though, where the country code is part of the input field. Maybe there should be an additional flag in the props for that? Since setting a country using the country
prop always hides the country code in the input field, and countrySelectComponent
doesn't seem to do anything at all.
@ianmartorell I see, so it works then. I guess I'll release it as a subpackage then.
I couldn't figure out how to replicate the behaviour in the "Force international format" example though, where the country code is part of the input field.
There currently is no such mode because I personally thought that it's a better UX when the country code is outside of the input field.
Maybe it's not always.
Whatever.
There could be a special inputCountryCallingCode: boolean
property if the feature was implemented in some hypothetical future.
I ended up implementing it with the country code inside the picker, but I think it would've looked good too with the country code in the field and just a flag in the picker. Maybe it's better UX like you said, but I guess it's good to let the user choose.
Published react-phone-number-input@3.1.0
with the React Native component included under /react-native-input
subpackage.
I ended up implementing it with the country code inside the picker, but I think it would've looked good too with the country code in the field and just a flag in the picker. Maybe it's better UX like you said, but I guess it's good to let the user choose.
Also added a new withCountryCallingCode: boolean
property of the /input
component that enables the type of feature you were describing.
We're using
import React, {useState, useEffect} from 'react';
import PhoneInput from 'react-phone-number-input/react-native-input';
import i18nGlobal from '../../utils/i18nGlobal';
const i18n = i18nGlobal.i18n;
function AuthScreen(props) {
const [phone, setPhone] = useState();
return (
<PhoneInput
placeholder={i18n.t('auth_screen.phone_input_text')}
defaultCountry="US"
value={phone}
onChange={setPhone}
/>
);
}
We're getting the error: Error: [libphonenumber-js]
metadataargument was passed but it's not valid metadata. Must be an object having
.countrieschild object property. Got a string: US.
@seamive See if react-phone-number-input@3.1.17
doesn't have the error.
@catamphetamine Hi! Could you add style
and placeholderTextStyle
props into PhoneInput
component? It'd make styling much more painless
@vpodolyan All rest
props should be passed through to the input component.
If something isn't passed through, then you should debug it in the code of the library.
Parent props aren't being passed to children, ...rest
solve this
placeholder, autoFocus, value
it's not necessary
This solves style
and placeholderTextColor
problems
import React, { useCallback } from 'react'
import PropTypes from 'prop-types'
import { TextInput } from 'react-native'
/**
* This is an _experimental_ React Native component.
* Feedback thread: https://github.com/catamphetamine/react-phone-number-input/issues/296
*/
function PhoneTextInput({
autoComplete,
onChange,
...rest
}, ref) {
// Instead of `onChangeText` it could use `onChange` and get `value` from `nativeEvent.text`.
const onChangeText = useCallback((value) => {
onChange({
preventDefault() { this.defaultPrevented = true },
target: { value }
})
}, [onChange])
return (
<TextInput
ref={ref}
autoCompleteType={autoComplete}
keyboardType="phone-pad"
onChangeText={onChangeText}
{...rest}/>
)
}
PhoneTextInput = React.forwardRef(PhoneTextInput)
PhoneTextInput.propTypes = {
autoComplete: PropTypes.string,
onChange: PropTypes.func.isRequired
}
export default PhoneTextInput
@gabrielmar cool!
@catamphetamine could you make this fix in the next release? It'd be very helpful.
Published react-phone-number-input@3.1.23
Thank you very much!
Added a PR to allow inputComponent to be specified.
https://gitlab.com/catamphetamine/react-phone-number-input/-/merge_requests/10
the import statement "import PhoneInput from 'react-phone-number-input/react-native-input';" is giving a "could not find declaration file for module" error.
How can I work around/fix this issue?
Is that actually a functional issue? I think typescript just wants you to add a .d
to what? theres a @types/react-phone-number-input but I don't see an equivalent for the react-native-input
There isn't one, hence the error. Might be worth a PR but that's not causing functional issues is it?
I've followed the example exactly but the component isn't showing up on the emulator and that's the only issue vsc is highlighting
I'm seeing the same warning but the control is working fine on the iOS simulator and react native web at the least, so it's likely something else. Any chance you can throw up a snack that shows your issue https://snack.expo.dev/?
Update: added inputComponent
property on the React Native phone input component for things like "Material UI" input, etc. Didn't test it but I don't think it could possibly break. The component seems kinda matured at this point so I've removed the "experimental" note from the updated readme.
@cgrady3 I was planning to add TypeScript "typings" to this library this weekend. Maybe tomorrow.
@cgrady3
Added TypeScript "typings" in react-phone-number-input@3.1.32
.
In case of any issues, open an issue.
@catamphetamine thank you for that. However, now it's giving the same error for every file it references (PhoneTextInput, PhoneInput, InputBasic, PropTypes, etc.)
I just wanted to mention something, I tried to implement using refs as suggested before but I didn't quite get it working. ChatGPT suggest using a prop I wasn't aware of called inputProps
(doesn't seem to be in the docs) to be used alongside inputComponent
and it works beautifully, I can now access any props in the TextInput via props I specify in the inputComponent prop