为什么这个输入 "value" 属性 没有刷新?

Why is the this input "value" property not refreshed?

我在用它做一个新项目时正在学习 React。

我想创建一个输入组件,其事件仅在用户退出输入或按下回车键时触发。 (here is the link to codesandbox)

const MyInput = ({ value, onValueChange }) => {
  const [myCurrentTypingValue, setMyCurrentTypingValue] = useState(value);

  useEffect(() => setMyCurrentTypingValue(value), [value]);

  const commitChanges = () => {
    const numericValue = Number(myCurrentTypingValue);
    setMyCurrentTypingValue(numericValue);

    if (value !== numericValue) onValueChange(numericValue);
  };

  const handleOnChange = (e) => setMyCurrentTypingValue(e.target.value);
  const handleOnBlur = () => commitChanges();
  const handleOnKeyPress = (e) => {
    if (e.charCode === 13) commitChanges();
  };

  return (
    <input
      type="number"
      value={myCurrentTypingValue}
      onChange={handleOnChange}
      onBlur={handleOnBlur}
      onKeyPress={handleOnKeyPress}
    />
  );
};

如你所见,当我输入一些东西时,当我按回车或退出时输入正确显示,但是当我输入以0开头的数字(例如000023)时,虽然数值被正确转换,它仍然显示为前面全为零。

因为我改变了我的组件的状态,我希望我的输入框值属性被刷新,但它不是:

为什么会这样?我用调试器工具检查过,我的状态是正确的吗?

如何让输入框以正确的数字格式值反映新状态?

当需要“提交”您的更改时,您应该将已解析的 number 值字符串化并更新输入值(始终为 string)。这是一个 self-contained 示例:

TS Playground

body { font-family: sans-serif; }
input[type="number"], pre { font-size: 1rem; padding: 0.5rem; }
<div id="root"></div><script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/standalone@7.17.10/babel.min.js"></script>
<script type="text/babel" data-type="module" data-presets="env,react">

// import * as ReactDOM from 'react-dom/client';
// import {useEffect, useState} from 'react';

// This Stack Overflow snippet demo uses UMD modules instead of the above import statments
const {useEffect, useState} = React;

// Parse a string as a number, but if the string is not a valid number then return 0
function parseNumber (str) {
  const n = Number(str);
  return Number.isNaN(n) ? 0 : n;
}

function NumberInput ({value, setValue}) {
  const [rawValue, setRawValue] = useState(String(value));

  useEffect(() => setRawValue(String(value)), [value]);

  const commit = () => setValue(parseNumber(rawValue));

  const handleChange = (ev) => setRawValue(ev.target.value);

  const handleKeyUp = (ev) => {
    if (ev.key === 'Enter') commit();
  };

  return (
    <input
      type="number"
      onBlur={commit}
      onChange={handleChange}
      onKeyUp={handleKeyUp}
      value={rawValue}
    />
  );
}

function App () {
  const [value, setValue] = useState(0);

  return (
    <div>
      <h1>Number input management</h1>
      <NumberInput {...{value, setValue}} />
      <pre><code>{JSON.stringify({value}, null, 2)}</code></pre>
    </div>
  );
}

const reactRoot = ReactDOM.createRoot(document.getElementById('root'));
reactRoot.render(<App />);

</script>