在onKeyDown之前反应输入onChange

const {useMemo, useState, createRef} = React;
const InputPIN = (props) => {
  const inputRefs = useMemo(() => Array(4).fill(0).map(i=> createRef()), []);
  const [values, setValues] = useState(Array(4).fill(''));
  function handleChange(e, index){
    const typed = e.target.value.toString();
    setValues((prev)=>
      prev.map((i,jndex) => {
        if(index === jndex) return typed[typed.length-1];
        else return i;
      })
    );
    if (typed !=='' &&  inputRefs[index + 1]) inputRefs[index + 1].current.focus();
  }
  function handleBackspace(e, index) {
    if(e.keyCode === 8){
      if(inputRefs[index-1]){
        inputRefs[index - 1].current.focus();
      }
    }
  }
  return (
    <label className="InputPIN">
      {
        new Array(4).fill(0).map((i,index)=>(
        <input style={{width:50}} key={index} value={values[index]} onKeyDown={(e)=>handleBackspace(e,index)} type="text" ref={inputRefs[index]} onChange={(e)=>handleChange(e,index)} /> ) )
      }
    </label>
  )
}

const App = () => {
  return (
    <InputPIN />
  )
}

ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

I am making an InputPIN component.

当我键入文本时,输入焦点将移至下一个输入。

当我键入退格键时,删除当前文本后,输入焦点将移至上一个输入。但这行不通。

on my code, I am using onKeyDown() and onChange(). and I guess onKeyDown() has a higher priority than onChange().

so, I've tried to change onKeyDown() to onKeyUp(). but it has a side effect that I don't want.

评论
  • 禽小兽
    禽小兽 回复

    Couldn't you use just one handling function, the handleChange one? By clicking backspace on an input, the value should be removed by default, so you just need to handle the focus on another element.

    Can you try adding to the <input>s element just the handleChange, and write the handleChange as follow:

    function handleChange(e, index) {
        // Handling change of input.
        const typed = e.target.value.toString();
        setValues((prev) =>
          prev.map((i,jndex) => {
            if(index === jndex) return typed[typed.length-1];
            else return i;
          })
        );
    
        // Handling focusing previous input
        if (e.keyCode === 8 && inputRefs[index - 1]) {
            inputRefs[index - 1].current.focus();
        }
        // Handling focusing next input
        else if (e.keyCode !== 8 && typed !== '' &&  inputRefs[index + 1]) {
            inputRefs[index + 1].current.focus();
        }
    }
    

    By the way, since setValues is asynchronous, you may get the change of focus before the actual change on the state in REACT component.
    If you would like to avoid that, you would need using a useEffect.