编程语言如何实现受控组件

    作者:卡颂更新于: 2020-11-19 12:11:13

    大神带你学编程,欢迎选课

    React源码中如何实现受控组件。编程语言(programming language)是一种被标准化的交流技巧,用来向计算机发出指令,定义计算机程序,让程序员能够准确地定义计算机所需要使用的数据,并精确地定义在不同情况下所应当采取的行动的一种计算机语言。 编程语言可以分成机器语言、汇编语言、高级语言三大类。计算机领域已发明了上千不同的编程语言,而且每年仍有新的编程语言诞生。

    今天我们站在框架开发者的角度来聊聊如何实现受控组件。

    编程语言如何实现受控组件_编程语言视频_汇编语言视频课程_编程开发视频_课课家

    今天我们站在框架开发者的角度来聊聊如何实现受控组件。

    在React中一个简单的受控组件如下:

    1. function app() { 
    2.   const [num, updateNum] = React.useState(0); 
    3.    
    4.   const onChange = ({target: {value}}) => { 
    5.     updateNum(value); 
    6.   } 
    7.  
    8.   return ( 
    9.      
    10.   ) 

    在onChange中会更新num,num作为value prop传递给,达到value受控的目的。

    如果让你来设计,你会怎么做?

    我相信大部分同学第一个想法是:将value prop与其他attribute prop一样处理就行。

    我们知道React内部运行有3个阶段:

    • schedule 调度更新阶段
    • render 进行diff算法的阶段
    • commit 进行DOM操作的阶段

    假设我们要在onChange中触发更新改变className,只需要在render阶段记录要改变的className,在commit阶段执行对应的addClass DOM操作。

    同样的,如果我们要在onChange中触发更新改变value,只需要在render阶段记录要改变的value,在commit阶段执行对应的inputDOM.setAttribute('value', value)操作。

    这样逻辑非常通顺。那么事实上呢?

    直接改变value的问题
    className只是inputDOM上的一个普通属性。而value则涉及到输入框光标的位置。

    如果我们直接修改value,那么属性改变后input的光标输入位置也会丢失,光标会跳到输入框的最后。

    想想我们将1234修改为12534。

    1. 1234 --> 12534 

    需要先将光标位置移动到2之后,再输入5。

    如果setAttribute('value', '12534'),那么光标不会保持在5后面而是跳到4后面。

    那么React如何解决这个问题呢?

    用非受控的形式实现受控组件

    你没有看错,React用非受控形式实现了受控组件的逻辑。

    简单的说,不同于className在commit阶段受控更新,value则完全是非受控的形式,只在必要的时候受控更新。

    因为一旦更新value,那么光标位置就会丢失。

    我们稍微修改下Demo,input为受控组件,value始终为1:

    1. function App() { 
    2.   const num = 1; 
    3.  
    4.   return ( 
    5.      
    6.   ) 

    当我们在源码中打上断点,输入2后,实际上会先显示12,再删掉2。

    只不过这个删除的过程是同步的所以看起来输入框内始终只有1。

    所以,不同于React其他组件props的更新会经历schedule - render - commit流程。

    对于input、textarea、select,React有一条单独的更新路径,这条路径触发的更新被称为discreteUpdate。

    这条路径的工作流程如下:

    1. 先以非受控的形式更新表单DOM
    2. 以同步的优先级开启一次更新
    3. 更新后的value在commit阶段并不会像其他props一样作用于DOM
    4. 调用restoreStateOfTarget方法,比较DOM的实际value(即步骤1中的非受控value)与步骤3中更新的value,如果相同则退出,如果不同则用步骤3的value更新DOM

    什么情况下这2个value会相同呢?

    我们正常的受控组件就是相同的情况:

    1. function App() { 
    2.   const [num, updateNum] = React.useState(0); 
    3.    
    4.   const onChange = ({target: {value}}) => { 
    5.     updateNum(value); 
    6.   } 
    7.  
    8.   return ( 
    9.      
    10.   ) 

    什么情况下这2个value会不同呢?

    上面的Demo中,虽然受控,但是没有调用updateNum更新value的情况:

    1. function App() { 
    2.   const num = 1; 
    3.  
    4.   return ( 
    5.      
    6.   ) 

    在这种情况下,步骤1的非受控value变为了12,步骤3的受控value还是1,所以最终会用1再更新下DOM的value。

    总结
    可以看到,要实现一个完备的前端框架,是有非常多细节的。

    为了实现受控组件,就得脱离整体更新流程,单独实现一套流程。

    编程语言原本是被设计成专门使用在计算机上的,但它们也可以用来定义算法或者数据结构。正是因为如此,程序员才会试图使程序代码更容易阅读。

课课家教育

未登录