Как получить динамическую ссылку и сосредоточиться в компоненте TextInput на React Native

#javascript #reactjs #typescript #react-native #loops

Вопрос:

Всем привет и заранее благодарю вас.

У меня есть экран, на котором я динамически генерирую текстовый ввод (по умолчанию количество сгенерированных текстовых вводов равно 4), но из родительского компонента вы можете указать, сколько входных данных вы хотите иметь в представлении.

Мне удалось динамизировать генерацию входных данных, но мне нужно динамизировать ссылки, и я не могу найти способ.

В том виде, в каком он есть на данный момент, он идеально работает для 4 входов, но если я создам его из родительского компонента с 2 входами, он сломается.

Это и есть код:

 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 amp;amp; refSecondInput.current.focus()
              : i === 1
              ? text.length > 0 amp;amp; refThirdInput.current.focus()
              : i === 2
              amp;amp; text.length > 0 amp;amp; refFourthInput.current.focus()
              
            console.log('PIN: ', pin)
          }}
          value={pin[i]}
          onKeyPress={({ nativeEvent }) => {
            nativeEvent.key === 'Backspace' amp;amp;
            i === 3 amp;amp; refThirdInput.current.focus() ||
            i === 2 amp;amp; refSecondInput.current.focus() ||
            i === 1 amp;amp; 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
              amp;amp; refFourthInput
          }
          autoFocus={i === 0 amp;amp; true}
          />
      )
    }

    return (
      <View style={{ flexDirection: 'row', justifyContent: 'center' }}>
        {inputs}
      </View>
    )
  }

  return <>{_getInputs(length || 4)}</>
}

export default PinCode


 

Теперь отлично работает с 4 входами, но не работает с другим количеством входов.

Нужны динамические ссылки для передачи внутри цикла for и использования его в onChangeText и onKeyPress компонента TextInput.

Большое спасибо.

Ответ №1:

Я реализовал это во вводе OTP, сначала нам нужно создать объект, у которого есть все ссылки.

 const inputsRef = React.useRef(inputs.map(() => React.createRef<TextInput>()));
 

Входные данные представляют собой массив с количеством элементов, в вашем компоненте добавьте это:

 ref={inputsRef.current[index]}
 

и для доступа к ссылке используйте это :

 inputsRef?.current[index]?.current?.focus();
 

Комментарии:

1. Привет, Израиль, спасибо за ваш ответ. Не могли бы вы посмотреть ответ под вашим комментарием? Большое спасибо!!

Ответ №2:

Так хотелось!

 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 amp;amp; text.length > 0 amp;amp; mapRef[i   1].current.focus()
            text.length === 0 amp;amp; i > 0 amp;amp; mapRef[i].current.focus()
          }}
          value={pin[i]}
          onKeyPress={({ nativeEvent }) => {
            nativeEvent.key === 'Backspace' amp;amp;
              i > 0 amp;amp; 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

 

Комментарии:

1. Это не дает ответа на вопрос, это было бы более уместно в качестве комментария.