在受控的 React 数字输入中,如何修剪前导零?

问题描述

React docs 中,它说在受控组件中,“React 状态是“唯一的事实来源””。这似乎是正确的,除非有前导零的情况。在下面的示例中,您可以看到输入是受控的,但在前导零的情况下,输入值并不总是与状态值匹配。


测试

键入前导零,因此该值类似于 0010

您可以看到 state 中的值是一个整数 10,但输入显示的是 0010

我的第一个想法是这是因为组件实际上并没有重新渲染,这是真的。 1010 之间没有状态变化,所以没有新的渲染。这是确认的,因为我们没有看到“渲染”console.log 触发。

因此,让我们确保更改该值。添加 2 以将 0010 更改为 00102。 state 中的值现在是 102,我们确认组件重新渲染...但前导零仍然存在于输入中。


这似乎不一致,因为我希望输入中的值始终与 state 中的值完全匹配。这是为什么?从数字输入中修剪前导零的可靠方法是什么?

// LEADING ZEROS INPUT TEST
// Step 1: type 0s into the input followed by any other digits
// Step 2: see that console log and val in `p` do not have leading 0's and input val does

const {useState} = React;

const App = () => {
  const [val,setVal] = useState(10);
  
  const handleChange = (evt) => {
    const strVal = evt.currentTarget.value;
    console.log('string',strVal,typeof strVal);
    const intVal = parseInt(strVal,10) || 0; // || 0 bc '' returns NaN
    console.log('int',intVal,typeof intVal);
    setVal(intVal);
  }
  
  console.log('render',val);
  
  return (
    <div>
      <p>{val}</p>
      <input 
        type="number"
        value={val}
        onChange={handleChange}
      />
    </div>
  )
}

ReactDOM.render(
  <App />,document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

解决方法

既然您已经知道为什么,我将帮助您了解如何

在我看来,一种从数字输入中修剪前导零的可靠方法是“模糊”,这会减少干扰并提供更好的用户体验。

const {useState,useCallback} = React;

const App = () => {
  const [val,setVal] = useState(10);
  const [strVal,setStrVal] = useState("10"); // To keep a reference of the real input value
  
  const handleChange = (evt) => {
    const inputVal = evt.currentTarget.value;
    setStrVal(inputVal);
    setVal(parseInt(evt.currentTarget.value,10) || 0);
  }

  const handleBlur = useCallback((evt) => {
    setStrVal(val.toString());
  },[val]);
  
  return (
    <div>
      <p>{val}</p>
      <input
        type="number"
        value={strVal}
        onChange={handleChange}
        onBlur={handleBlur}
      />
    </div>
  )
}

ReactDOM.render(
  <App />,document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>