Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(React Native) Can this package be used in the React Native? #296

Open
irsyaadbp opened this issue Nov 12, 2019 · 70 comments
Open

(React Native) Can this package be used in the React Native? #296

irsyaadbp opened this issue Nov 12, 2019 · 70 comments

Comments

@irsyaadbp
Copy link

Can this package be used in the react native

@catamphetamine
Copy link
Owner

catamphetamine commented Nov 12, 2019

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.

@catamphetamine
Copy link
Owner

Also see the previous question: #283 (comment)

@whimsicaldreamer
Copy link

whimsicaldreamer commented Jan 20, 2020

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

@catamphetamine
Copy link
Owner

@whimsicaldreamer

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

@whimsicaldreamer
Copy link

whimsicaldreamer commented Jan 21, 2020

@catamphetamine

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?

@catamphetamine
Copy link
Owner

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.

@whimsicaldreamer
Copy link

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?

@catamphetamine
Copy link
Owner

You mean to pass in the react native TextInput component here?

Yes.

@catamphetamine
Copy link
Owner

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.

@whimsicaldreamer
Copy link

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.

@catamphetamine
Copy link
Owner

Yes, see if it works.
I don't have React Native so I didn't check.

@whimsicaldreamer
Copy link

@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')

@catamphetamine
Copy link
Owner

catamphetamine commented Jan 22, 2020

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

@whimsicaldreamer
Copy link

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.

@catamphetamine
Copy link
Owner

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?

@whimsicaldreamer
Copy link

Yes, the forward ref warning disappeared but I get the TypeError.

@catamphetamine
Copy link
Owner

catamphetamine commented Jan 23, 2020 via email

@whimsicaldreamer
Copy link

whimsicaldreamer commented Jan 23, 2020

I guess input-format is only for react.

Screenshot_2020-01-23-22-09-05-727_com furry

@catamphetamine
Copy link
Owner

catamphetamine commented Jan 24, 2020

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.

const InputComponent = smartCaret ? InputSmart : InputBasic

So, see if such code works:

import PhoneInput from 'react-phone-number-input/input`

<PhoneInput smartCaret={false} .../>

@whimsicaldreamer
Copy link

whimsicaldreamer commented Jan 24, 2020

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

Screenshot_2020-01-24-11-38-40-638_com furry

@catamphetamine
Copy link
Owner

catamphetamine commented Jan 24, 2020 via email

@whimsicaldreamer
Copy link

Screenshot_2020-01-24-16-31-41-572_com furry

@catamphetamine
Copy link
Owner

So event.target.value is undefined at this line of code:

let newValue = parseIncompletePhoneNumber(event.target.value)

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

@whimsicaldreamer
Copy link

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}

@catamphetamine
Copy link
Owner

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.

@whimsicaldreamer
Copy link

I guess we get the values from nativeEvent.text.

@whimsicaldreamer
Copy link

<PhoneTextInput onTextChange={value => onChange({
  preventDefault() { this.defaultPrevented = true },
  target: { value }
})}/>

Where should I try the above?

@catamphetamine
Copy link
Owner

@whimsicaldreamer

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

@whimsicaldreamer
Copy link

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.

@catamphetamine
Copy link
Owner

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.

@catamphetamine catamphetamine changed the title (React Native) Can this package be used in the React Native? (React Native) Can this package be used in the React Native? Feb 5, 2020
@whimsicaldreamer
Copy link

@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! ;)

@catamphetamine
Copy link
Owner

@whimsicaldreamer

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 )

@whimsicaldreamer
Copy link

so I'm not a specialist in it

Neither am I. :(

Don't have time for everything in this world

True for everyone. :)

@nandorojo
Copy link

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?

@catamphetamine
Copy link
Owner

@nandorojo

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

@ianmartorell
Copy link

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.

@catamphetamine
Copy link
Owner

catamphetamine commented Jun 3, 2020

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

@ianmartorell
Copy link

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.

@catamphetamine
Copy link
Owner

Published [email protected] with the React Native component included under /react-native-input subpackage.

@ianmartorell

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.

@teamseamive
Copy link

teamseamive commented Mar 9, 2021

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.

@catamphetamine
Copy link
Owner

@seamive See if [email protected] doesn't have the error.

@vpodolyan
Copy link

@catamphetamine Hi! Could you add style and placeholderTextStyle props into PhoneInput component? It'd make styling much more painless

@catamphetamine
Copy link
Owner

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

@gabrielmar
Copy link

Parent props aren't being passed to children, ...rest solve this
placeholder, autoFocus, value it's not necessary

This solves style and placeholderTextColor problems

https://gitlab.com/catamphetamine/react-phone-number-input/-/blob/master/source/react-native/PhoneTextInput.js

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

@vpodolyan
Copy link

@gabrielmar cool!
@catamphetamine could you make this fix in the next release? It'd be very helpful.

@catamphetamine
Copy link
Owner

Published [email protected]

@vpodolyan
Copy link

Thank you very much!

@kav
Copy link

kav commented Sep 28, 2021

Added a PR to allow inputComponent to be specified.
https://gitlab.com/catamphetamine/react-phone-number-input/-/merge_requests/10

@cgrady3
Copy link

cgrady3 commented Sep 30, 2021

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?

@kav
Copy link

kav commented Sep 30, 2021

Is that actually a functional issue? I think typescript just wants you to add a .d

@cgrady3
Copy link

cgrady3 commented Sep 30, 2021

to what? theres a @types/react-phone-number-input but I don't see an equivalent for the react-native-input

@kav
Copy link

kav commented Sep 30, 2021

There isn't one, hence the error. Might be worth a PR but that's not causing functional issues is it?

@cgrady3
Copy link

cgrady3 commented Sep 30, 2021

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

@kav
Copy link

kav commented Oct 1, 2021

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

@catamphetamine
Copy link
Owner

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.

@catamphetamine
Copy link
Owner

@cgrady3 I was planning to add TypeScript "typings" to this library this weekend. Maybe tomorrow.

@catamphetamine
Copy link
Owner

@cgrady3
Added TypeScript "typings" in [email protected].
In case of any issues, open an issue.

@cgrady3
Copy link

cgrady3 commented Oct 8, 2021

@catamphetamine thank you for that. However, now it's giving the same error for every file it references (PhoneTextInput, PhoneInput, InputBasic, PropTypes, etc.)

@jacquesdev
Copy link

jacquesdev commented Jul 2, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests