今天我们站在框架开发者的角度来聊聊如何实现受控组件。
田家庵网站建设公司成都创新互联,田家庵网站设计制作,有大型网站制作公司丰富经验。已为田家庵上1000+提供企业网站建设服务。企业网站搭建\外贸营销网站建设要多少钱,请找那个售后服务好的田家庵做网站的公司定做!
在React中一个简单的受控组件如下:
- function App() {
- const [num, updateNum] = React.useState(0);
- const onChange = ({target: {value}}) => {
- updateNum(value);
- }
- return (
- )
- }
在onChange中会更新num,num作为value prop传递给,达到value受控的目的。
如果让你来设计,你会怎么做?
我相信大部分同学第一个想法是:将value prop与其他attribute prop一样处理就行。
我们知道React内部运行有3个阶段:
假设我们要在onChange中触发更新改变className,只需要在render阶段记录要改变的className,在commit阶段执行对应的addClass DOM操作。
同样的,如果我们要在onChange中触发更新改变value,只需要在render阶段记录要改变的value,在commit阶段执行对应的inputDOM.setAttribute('value', value)操作。
这样逻辑非常通顺。那么事实上呢?
直接改变value的问题
className只是inputDOM上的一个普通属性。而value则涉及到输入框光标的位置。
如果我们直接修改value,那么属性改变后input的光标输入位置也会丢失,光标会跳到输入框的最后。
想想我们将1234修改为12534。
- 1234 --> 12534
需要先将光标位置移动到2之后,再输入5。
如果setAttribute('value', '12534'),那么光标不会保持在5后面而是跳到4后面。
那么React如何解决这个问题呢?
用非受控的形式实现受控组件
你没有看错,React用非受控形式实现了受控组件的逻辑。
简单的说,不同于className在commit阶段受控更新,value则完全是非受控的形式,只在必要的时候受控更新。
因为一旦更新value,那么光标位置就会丢失。
我们稍微修改下Demo,input为受控组件,value始终为1:
- function App() {
- const num = 1;
- return (
- )
- }
当我们在源码中打上断点,输入2后,实际上会先显示12,再删掉2。
只不过这个删除的过程是同步的所以看起来输入框内始终只有1。
所以,不同于React其他组件props的更新会经历schedule - render - commit流程。
对于input、textarea、select,React有一条单独的更新路径,这条路径触发的更新被称为discreteUpdate。
这条路径的工作流程如下:
什么情况下这2个value会相同呢?
我们正常的受控组件就是相同的情况:
- function App() {
- const [num, updateNum] = React.useState(0);
- const onChange = ({target: {value}}) => {
- updateNum(value);
- }
- return (
- )
- }
什么情况下这2个value会不同呢?
上面的Demo中,虽然受控,但是没有调用updateNum更新value的情况:
- function App() {
- const num = 1;
- return (
- )
- }
在这种情况下,步骤1的非受控value变为了12,步骤3的受控value还是1,所以最终会用1再更新下DOM的value。
总结
可以看到,要实现一个完备的前端框架,是有非常多细节的。
为了实现受控组件,就得脱离整体更新流程,单独实现一套流程。
本文名称:React源码中如何实现受控组件
文章网址:http://www.mswzjz.com/qtweb/news42/162542.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联