抽象与复用:usePropsValue
到这里,我们已经基本实现了所有的功能,但我们只是实现了一个 Input 组件,在 antd-mobile 这样的组件库中,会有很多很多组件都需要支持能够切换受控和非受控模式。所以,为了更好的可复用性,我们把上面的逻辑抽离成一个自定义 Hook:
这样,在各种组件中,我们可以直接使用 usePropsValue
,用法和 useState
非常接近:
不过,我们忽略了 defaultValue
,在 antd-mobile 中,value
onChange
defaultValue
总是成组出现的:
接下来,让我们对它再做一点优化,让它变得更像 useState
。useState
得到的 setState
函数,支持传入一个更新函数,而 usePropsValue
目前还不支持这种用法,所以我们来改造一下:
一个隐藏的小 bug
我本以为已经完工了,直到某天在 GitHub 上收到了一条 issue:TabBar 的 onChange 为什么在同 key 的情况也会触发 #5409[1]。
这条 issue 揭示了一个隐藏已久的 bug,举个例子:
假如当前的 state
为 1
,如果我们用的是 React 的 useState
,那执行 setState(1)
不会有任何效果,React 会帮我们过滤掉这次的更新。而 usePropsValue
不会。
对用户来说,点击同一个 Tab 并没有触发切换,也因此不应该触发 onChange
事件,所以我们还需要额外的增加一点判断,来解决这个 bug:
在 antd-mobile 中,我们也有一个这样的 usePropsValue
工具 Hook,和上面文章中所描述的几乎是一样的,如果你想了解更多,可以去这里[2]翻阅代码。
勘误
上面“解决问题 2:性能”章节中提到“React 不允许我们在 render 过程中调用 setState
”,但经评论区
@fenoob[3]
指正,其实是 React 是允许我们在 render 函数中调用 setState
的,只是限制了只能触发当前组件自己的 state 更新。我在这里写了一个 demo[4] 验证了一下。
参考资料
[1]
TabBar 的 onChange 为什么在同 key 的情况也会触发 #5409:https://github.com/ant-design/ant-design-mobile/issues/5409
[2]
[3]
@fenoob://www.zhihu.com/people/05bdf67112572afd5f3526f2eaa425c8
[4]
demo:https://codesandbox.io/s/condescending-pare-1utvlt?file=/src/App.js
[5]
antd mobile:https://github.com/ant-design/ant-design-mobile