【like-react】手寫一個類似 react 的框架


平時寫寫 react,卻不了解內部是怎么把 jsx 轉化為 vdom,然后渲染在界面上,以及當數據流更新時,視圖又是怎么更新的呢。 

於是我查閱了大量資料后,自己手寫了一個簡單版的 react,從中大概能了解到 react 基本的運行機制。

 react 一個很方便之處是我們可以像寫原生 html 那樣寫組件,這就是 jsx 語法,那么 jsx 是如何轉化為 dom 的呢。首先通過 babel 語法樹解析轉化成為 vdom,它的結構大概是

/* <div id="container">xxxxxx</div> */
{ type:
'div', props: { id: 'container' }, children: ['xxxxx'] }

之后通過 react 內部的 render 方法將 vdom 轉為 dom 節點。

render 方法實現如下:

const _render = (vdom, parent = null) => {
    // custom component 經過 babel 轉義 然后 React.createElement 返回的 vdom.type 類型是 function
    // <p id="label">title</p> vdom = { type: 'p', props: {id: 'label'}, children: ['title']}
    const mount = parent ? (el => parent.appendChild(el)) : (el => el);
    if (typeof vdom === 'string' || typeof vdom === 'number') {
      return mount(document.createTextNode(vdom));
    } if (typeof vdom === 'boolean' || vdom === null) {
      return mount(document.createTextNode(''));
    } if (typeof vdom === 'object' && typeof vdom.type === 'function') {
      return Component.render(vdom, parent);
    } if (typeof vdom === 'object' && typeof vdom.type === 'string') {
      const dom = mount(document.createElement(vdom.type));
      for (const child of [].concat(...vdom.children)) _render(child, dom);
      for (const prop in vdom.props) {
        if (Object.prototype.hasOwnProperty.call(vdom.props, prop)) {
          setAttribute(dom, prop, vdom.props[prop]);
        }
      }
      return dom;
    }
    throw new Error(`Invalid VDOM: ${vdom}.`);
  };

值得一提的是在 ReactDOM.render() 時,首先會遍歷所有節點,然后實例化節點,調用 componentWillMount 方法,接着 調用內部的 render 將 vdom 轉化為 真實 dom,接受一個 標識符 key 值,這在更新組件時將會派上用場。緊接着調用 componentDidMount 方法。

接下來講一下 react 更新 state 時發生了什么。眾所周知,傳統的比較兩棵樹是否相同的時間復雜度是 O(n^3),而 react 基於一套比較規則將時間復雜度降到了 O(n),這大大提高了計算的時間,提高了渲染的速度。因此 react 在更新狀態時的 patch 方法都做了什么。其實就是基於 react 的比較算法:1. 兩棵樹的節點類型都不同時則整棵樹都替換;2.當節點的 key 值相同時則直接遞歸比較所有子節點。

 

詳細實現參見: https://github.com/Vxee/like-react


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM