anujs1.4.0發布


經過三個月的埋頭苦干,終於完成Fiber版的anujs。
主要特性有:

  • 測試全部改成jest, 遷移官方測試用例。有許多迷你React吹得怎么天花亂墜,但是生命周期鈎子的執行順序無法與官方保持一致,那么就很難共享React龐大的資源。像深度使用React內部 機制的ReactRouter與antd就無法使用。
    支持新鈎子,包括getDerivedStateFromProps,getDerivedStateFromCatch, getSnapshotBeforeUpdate,componentDidCatch。新鈎子的誕生與已有的三個componentWillXXX 鈎子的廢棄是同步進行的,你在組件里定義了新鈎子,那舊鈎子就不會被調起。
    支持批量更新API,ReactDOM.unstable_batchedUpdates, 這原本在React15的事件回調執行setState就存在的一種優化技術。現在官方將它大眾化。
    將createClass移出核心庫,已經2018年了,應該接受es6的洗禮。
    重構錯誤邊界,只差一個用例就跑通官方測試了。
    重構受控組件,全部用例跑通。
    更新划分目錄,源碼放在packages下,分成core, fiber與render。core對應react.js,包括一些公用方法與內置組件(Fragment組件, Portal組件, PureComponent組件, forwardRef高階組件)。fiber就是React16的異步架構。render包含了不同的渲染器,dom, noop(測試用), server。職責分明,有利於后繼的調優。
    支持antd 99%組件,目前只發現transfer有點問題。

這里着重說一下fiber版塊下的設計。
unbatch內置了一個Unbatch組件,它用來模擬React內部的unbatchedUpdates。
scheduleWork里面有一個updateComponet方法,setState的真正實現,用於驅動某一棵樹的更新。ReactDOM.render(vdom, container, cb)也會調用它進行更新,不過在我們container與vdom中,我們放進了一個Unbatch組件。調用ReactDOM.render相當於調用了Unbatch組件的setState, setState有第二個可選參數cb, 也就相當於ReactDOM.render的第三個可選cb。updateComponet最里面是scheduleWork方法,它按理是使用大名鼎鼎的requestIdleCallback,現在沒有實現,臨時糊弄一下大家。

let deadline = {
   didTimeout: false,
   timeRemaining() {
      return 2;
   },
};

function requestIdleCallback(fn) {
   fn(deadline);
}
Renderer.scheduleWork = function() {
   performWork(deadline);
};

performWork的實現類似於早期的rAF動畫,發現還有任務沒完工,就繼續遞歸執行自身。

// rAF動畫的示范代碼
var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';

function step(timestamp) {
  if (!start) start = timestamp;
  var progress = timestamp - start;
  element.style.left = Math.min(progress / 10, 200) + 'px';
  if (progress < 2000) { //遞歸執行自身
    requestAnimationFrame(step);
  }
}

requestAnimationFrame(step)
performWork的代碼也是如此
function performWork(deadline) {
   //執行當前的所有任務,更新虛擬DOM與真實DOM
   workLoop(deadline);
   //忽略其他往macrotasks中添加任務的代碼。。。
   //忽略其他往macrotasks中添加任務的代碼。。。
   //忽略其他往macrotasks中添加任務的代碼。。。
   if (macrotasks.length) {
      requestIdleCallback(performWork);
   }
}

ReactFiber相當於偽造了一個瀏覽器,因此有自己調度器,事件列隊。於是你可以看到macrotasks,microtasks,batchedtasks, boundaries, effects等列隊。
macrotasks,宏列隊,主進程,一個頁面只有一個, ReactDOM.render就會將第一個參數丟進去。
2. microtasks,微列隊,子進程,每棵虛擬DOM樹都有一個,放在根節點中。當組件執行setState后,它會找到根節點的microtasks,然后放進去。然后在下次喚起performWork時,會從所有根節點中收集它們。
3. batchedtasks,批量處理的任務,它們不能被合並。microtasks中的任務,都是由setState產生的,我們知道對某個組件進行多次setState,React在一次生命周期中會執行一次更新。batchedtasks則不一樣,它們是延后到下次生命周期,因此不能在這次生命周期中就被執行了。
4. boundaries,放着邊界組件,邊界組件會有很高的優先級,確保它們下次在performWork中,加入macrotasks的最前面。
5. effects,它是commit階段執行的macrotasks 列隊。
workLoop有兩個DFS遍歷,reconcileDFS與commitDFS。reconcileDFS負責更新虛擬DOM,commitDFS負責更新真實DOM。為什么強調使用DFS,因為這東西對我們存取context, container非常方便。
注意:
anujs改動比較大,導致原先的DevTool不能用,這也是后繼的工作重點了。
雖然這次改動這么大,它的體積還是相當迷你的。

與1.3x一樣,它是對IE8友好的,它所有使用的es6新特性都可以被babel polyfill及使用es3ify優雅降級。目前已經有IE8專用的腳手架可用:https://gitee.com/menhal/React_IE8_boilerplate
剩下就是需要大家同心協力發掘兼容性很好的React路由庫與UI庫。

npm i anujs

webpack.config中如何代替原來用React編寫的項目

resolve: {
   alias: {
      'react': 'anujs',
      'react-dom': 'anujs',
        // 若要兼容 IE 請使用以下配置
        // 'react': 'anujs/dist/ReactIE',
        // 'react-dom': 'anujs/dist/ReactIE',
    
        // 如果引用了 prop-types 或 create-react-class
        // 需要添加如下別名
        'prop-types': 'anujs/lib/ReactPropTypes',
        'create-react-class': 'anujs/lib/createClass'
        //如果你在移動端用到了onTouchTap事件
        'react-tap-event-plugin': 'anujs/lib/injectTapEventPlugin',  
   }
},


免責聲明!

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



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