Реагируйте useRef с Array для динамического - PullRequest
0 голосов
/ 16 апреля 2020

Я пытаюсь сделать так, чтобы компонент перемещал фокус на следующий ввод при вводе каждой буквы.

Мне кажется, мне нужно несколько ref как массив, но я не знаю об этом.

Это пример кода для вопроса.

function PIN({length, onChange, value}){
  const inputEl = React.useRef(null);
  function handleChange(e){
    onChange(e);
    inputEl.current.focus(); 
  }
  return (
    <div>
      {
        new Array(length).fill(0).map((i)=>(
          <input type="text" ref={inputEl} onChange={handleChange} />
        ))
      }
    </div>
  )
}

Ответы [ 5 ]

2 голосов
/ 16 апреля 2020

Ссылка на вход эквивалентна функции обратного вызова. Вы можете передать ему метод. Параметр, полученный этим методом, является входным элементом dom, который можно сохранить в массиве.

import React from "react";
import "./styles.css";

export default function App() {
  const inputEl = React.useRef([]);
  function handleChange(i){
    inputEl.current[i+1].focus(); 
  }
  return (
    <div>
      {
        new Array(3).fill(0).map((n,i)=>(
          <input 
          key={i} 
          type="text" 
          ref={ref=>inputEl.current.push(ref)} 
          onChange={()=>handleChange(i)} 
          />
        ))
      }
    </div>
  )
}
2 голосов
/ 16 апреля 2020

Вы можете создать несколько ссылок

function PIN({length, onChange, value}){
  const inputRefs = useMemo(() => Array(length).fill(0).map(i=> React.createRef()), []);
  const handleChange = index => (e) => {
    //onChange(e); // don't know about the logic of this onChange if you have multiple inputs
    if (inputRefs[index + 1]) inputRefs[index + 1].current.focus(); 
  }
  return (
    <div>
      {
        new Array(length).fill(0).map((inp, index)=>(
          <input type="text" ref={inputRefs[index]} onChange={handleChange(index)} />
        ))
      }
    </div>
  )
}
1 голос
/ 16 апреля 2020

В ваших входах вы можете передать функцию параметру ref, это позволит вам сохранить все ваши ссылки в массиве:

let myRefs = [];

const saveThisRef = (element) => {
  myRefs.push(element);
}

Затем вы можете передать свою функцию каждому входу, который вы render:

<input type="text" ref={saveThisRef} onChange={handleChange} />

Затем вы можете перейти к следующему вводу в обработчике onChange:

// Find the index of the next element
const index = myRefs.indexOf(element) + 1;
// Focus it
if (index < myRefs.length) myRefs[index].focus();
0 голосов
/ 16 апреля 2020

Повторный рендеринг компонента, который содержит динамический c Список ссылок с другим числом ссылок вызывает исключение («Отрисовано больше хуков, чем во время предыдущего рендеринга»), как вы можете видеть в этом примере:

https://codesandbox.io/s/intelligent-shannon-u3yo6?file= / src / App. js

Вы можете создать новый компонент, который отображает один и содержит свой собственный единственный ref, и использовать родительский элемент для управления текущий сфокусированный ввод и передайте эти данные вашему новому компоненту, например.

0 голосов
/ 16 апреля 2020

Вот пример, который действительно будет работать:

const { useState, useCallback, useEffect, useRef } = React;

const Pin = ({ length, onChange, value }) => {
  const [val, setVal] = useState(value.split(''));
  const [index, setIndex] = useState(0);
  const arr = [...new Array(length)].map(
    (_, index) => index
  );
  const myRefs = useRef(arr);
  const saveThisRef = (index) => (element) => {
    myRefs.current[index] = element;
  };
  function handleChange(e) {
    const newVal = [...val];
    newVal[index] = e.target.value;
    if (index < length - 1) {
      setIndex(index + 1);
    }
    setVal(newVal);
    onChange(newVal.join(''));
  }
  const onFocus = (index) => () => {
    const newVal = [...val];
    newVal[index] = '';
    setIndex(index);
    setVal(newVal);
    onChange(newVal.join(''));
  };
  useEffect(() => {
    if (index < myRefs.current.length) {
      myRefs.current[index].focus();
    }
  }, [index, length, myRefs]);
  return arr.map((index) => (
    <input
      type="text"
      ref={saveThisRef(index)}
      onChange={handleChange}
      onFocus={onFocus(index)}
      value={val[index] || ''}
      maxLength="1"
      key={index}
    />
  ));
};
const App = () => {
  const [value, setValue] = useState('');
  const onChange = useCallback(
    (value) => setValue(value),
    []
  );
  console.log('value:', value);
  return (
    <Pin
      length={5}
      value={value}
      onChange={onChange}
    />
  );
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...