Hello everyone and thank you in advance.
I have a screen, where I dynamically generate TextInput (the default number of generated textInput is 4), but from the parent component you can indicate how many inputs you want to have in the view.
I have managed to dynamize the generation of inputs, but I need to dynamize the references and I can't find a way.
The way it is at the moment, it works perfect for 4 inputs, but if I create it from the parent component with 2 inputs, it breaks.
This is the code:
import React, { useRef } from 'react'
import { TextInputProps, View, TextInput } from 'react-native'
interface iPinCode extends TextInputProps {
onComplete: (code: string) => void
length?: number
}
const PinCode: React.FunctionComponent<iPinCode> = ({ onComplete, length }) => {
const inputStyle = {
height: 75,
width: 50,
fontSize: 26,
color: '#FFF',
backgroundColor: '#4B4B4B',
borderRadius: 15,
padding: 8,
margin: 4,
}
const _getInputs = (length: number) => {
let inputs: JSX.Element[] = []
let pin: string[] = []
let refFirstInput = useRef()
let refSecondInput = useRef()
let refThirdInput = useRef()
let refFourthInput = useRef()
for (let i = 0; i < length; i ) {
inputs.push(
<TextInput
key={i}
style={[inputStyle, { textAlign: 'center' }]}
onChangeText={text => {
text.length >= 1 ? pin.splice(i, 0, text) : pin.splice(i, 1)
i === 0
? text.length > 0 && refSecondInput.current.focus()
: i === 1
? text.length > 0 && refThirdInput.current.focus()
: i === 2
&& text.length > 0 && refFourthInput.current.focus()
console.log('PIN: ', pin)
}}
value={pin[i]}
onKeyPress={({ nativeEvent }) => {
nativeEvent.key === 'Backspace' &&
i === 3 && refThirdInput.current.focus() ||
i === 2 && refSecondInput.current.focus() ||
i === 1 && refFirstInput.current.focus()
}}
secureTextEntry
keyboardType="numeric"
maxLength={1}
returnKeyType={i === 3 ? 'done' : 'next'}
onSubmitEditing={() => { onComplete(pin.join('')); console.log('PIN TO SEND: ', pin.join(''))}}
ref={
i === 0
? refFirstInput
: i === 1
? refSecondInput
: i === 2
? refThirdInput
: i === 3
&& refFourthInput
}
autoFocus={i === 0 && true}
/>
)
}
return (
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
{inputs}
</View>
)
}
return <>{_getInputs(length || 4)}</>
}
export default PinCode
Now works perfectly with 4 inputs, but breack with other number of inputs.
Need dynamic refs to pass inside for loop and use it in onChangeText and onKeyPress of TextInput component.
Thanks a lot.
CodePudding user response:
I was implements this in OTP input, first we need to create a object that have the all refs.
const inputsRef = React.useRef(inputs.map(() => React.createRef<TextInput>()));
The inputs are an array with the number of elements, in your component add this:
ref={inputsRef.current[index]}
and for access to the reference, use this :
inputsRef?.current[index]?.current?.focus();
CodePudding user response:
Soooolved!
import React, { useRef } from 'react'
import { TextInputProps, View, TextInput } from 'react-native'
interface iPinCode extends TextInputProps {
onComplete: (code: string) => void
length?: number
}
const PinCode: React.FunctionComponent<iPinCode> = ({ onComplete, length }) => {
const inputStyle = {
height: 75,
width: 50,
fontSize: 26,
color: '#FFF',
backgroundColor: '#4B4B4B',
borderRadius: 15,
padding: 8,
margin: 4,
}
const _getInputs = (length: number) => {
let inputs: JSX.Element[] = []
let pin: string[] = []
const mapRef: any = []
for (let index = 0; index < length; index ) {
mapRef.push(useRef())
}
for (let i = 0; i < length; i ) {
inputs.push(
<TextInput
key={i}
style={[inputStyle, { textAlign: 'center' }]}
onChangeText={text => {
text.length === 1 ? pin.splice(i, 0, text) : pin.splice(i, 1)
i < length - 1 && text.length > 0 && mapRef[i 1].current.focus()
text.length === 0 && i > 0 && mapRef[i].current.focus()
}}
value={pin[i]}
onKeyPress={({ nativeEvent }) => {
nativeEvent.key === 'Backspace' &&
i > 0 && mapRef[i - 1].current.focus()
}}
secureTextEntry
keyboardType="numeric"
maxLength={1}
returnKeyType={length - 1 ? 'done' : 'next'}
onSubmitEditing={() => onComplete(pin.join(''))}
ref={mapRef[i]}
autoFocus={i === 0}
/>
)
}
return (
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
{inputs}
</View>
)
}
return <>{_getInputs(length || 4)}</>
}
export default PinCode