问题
一次写业务需求的时候,需要自己写一个input-number组件。这个input-number允许用户输入,将输入转为数字后重新展示。
于是马上写了一版:
但发现在给input-number输入”01”后,显示居然没有变成”1”
为什么会出现这种情况?你能猜到原因吗?
调试
经过对setState的学习,我们知道更新时,会调用_updateRenderedComponent方法,我们在这打上断点,看下后面都发生了什么。
进过一番折腾,终于找到input更新dom的地方了
调用栈
|
|
获取到新旧两个props后,会更新dom属性,我们的值不同,很可能是这里出的问题
我们进入_updateDOMProperties看看它是如何更新属性的
在调试时,我们仅需关注value,发现这里对value的主要处理为
继续追踪,函数执行到DOMPropertyOperations.setValueForProperty
是不是有点紧张,越来越接近答案了
辗转又进入
走到这,这里的node.ownerDocument.activeElement 等于 node,并没有去重置node的value值,而原因在注释中说明
don’t operate on inputs that have focus, otherwise Chrome might strip off trailing decimal places and cause the user’s cursor position to jump to the beginning of the input.
“不要对具有焦点的输入进行操作,否则Chrome可能会脱离尾随小数位并导致用户的光标位置跳转到输入的开头。”
这里没有去更新input的值,那有别的地方处理吗?
这段注释下面还有一句
In ReactDOMInput, we have an onBlur event that will trigger this function again when focus is lost.
说的是失去焦点时,会重新触发这个操作。
回到updateComponent方法,关于input,它还有一部分操作
看看wrapper里有没有对此input更新
注意到这里node.value 为 “01” 而 value为 1
而 “01” == 1,因此这里也没有更新,晕!
终于找着了罪魁祸首,这是不是React的bug呢?准备提一个issue去。
解决
方案一:手动更新
在componentDidUpdate里,我们去操作真实dom的value值
方案二:避免字符串与数字比较
可以将相关的state 改为string 类型