你也想做掌控全局的React 大師嗎?

blank

你也想做掌控全局的React 大師嗎?

你可能已經聽說過大名鼎鼎的why-did-you-update ,它能夠發現程序中不必要的重新渲染:

blank

其大致原理是將React.Component.prototype.componentDidUpdate覆蓋為一個新的函數,在其中進行了每次渲染前後的props的深度比較,並將結果以友好直觀的方式呈現給用戶。但它有一個明顯的缺陷——如果某一組件定義了componentDidUpdate 方法, why-did-you-update 就失效了。

想要解決上述問題、並且更進一步地了解其他生命週期的觸發情況,或者說,以上帝視角看到整個React 應用的運行情況,該怎麼做呢?

最直接的做法是,對每個組件修改其代碼或使用HoC 來達到目的。但有此類需求的項目體積往往已經具備一定規模,逐個修改代碼的做法是不可接受的,想像一下在每個組件的代碼都進行這樣的修改會是多麼繁瑣的工作:

class App extends React . Component { // 手动添加该方法componentDidUpdate () { // ... } render () { return 'Hello, World!' } } // 或者使用decorator @ addDidUpdate class App extends React . Component { render () { return 'Hello, World!' } }

那麼有沒有一款輕鬆易用,可以在一處監聽項目中所有組件的工具呢?

有!

react-lifecycle-hooks可以幫助你可以對項目中所有組件的React生命週期事件進行監聽,而完全不需要修改原有代碼

// 假设这是项目中已有的一个组件, app.js class App extends React . Component { render () { return 'Hello, World!' } }

//新建的監聽專用文件,在必要時引入你的項目import{activate,addMiddleware}from'react-lifecycle-hooks'importAppfrom'./path/to/app'activate()//這一行就都安排上了!//範例中間件,中間件在所有組件的所有生命週期觸發時被調用,你可以通過如下過濾實現定向監聽functionsimplyLog(componentClass,componentInstance,lifecycleName,lifecycleArguments){if(componentClass===App){console.log('Going to execute',lifecycleName,'of',componentClass.name,'on',componentInstance)}}addMiddleware(simplyLog)//從此開始,所有App組件上發生的事情會被simplyLog呈現於console

原理揭秘

是JSX ,我加了JSX 。

一切的秘密其實在JSX ,讓我們重新審視JSX :

<Componentprop={value}>{children}</Component>

JSX 是一種語法,在React 下其對應的原生JavaScript 表示約為

React.createElement(Component,{prop:value},children)

React 的每一次渲染實際上是多次調用了React.createElement 方法,生成對應的JavaScript Object (VDOM)來表達視圖。如果改寫該方法,將記錄每個傳入的Component ,就能追踪到所有被渲染的組件

核心代碼摘要:

const{createElement}=reactfunctiondecorate(componentClass){/* HoC */}react.createElement=function(type){if(typeoftype!=='function')returncreateElement.apply(this,arguments)// type是組件類或無狀態組件constdecorated=decorate(type)returncreateElement.apply(this,[decorated].concat(Array.prototype.slice.call(arguments,1)))}

於是每次渲染出的VDOM 中都是被decorate 方法處理過的新組件,帶有全套的生命週期方法。而且,由於新組件的生命週期是對原組件的巧妙包裝,使用react-lifecycle-hooks 不會對你的應用表現產生任何的影響,達到了無縫切入的效果。強烈建議你玩一下上方的在線demo !

展望

react-lifecycle-hooks 的不是開箱即用可以直接為你提高生產力、解決實際問題的庫,它只是提供了一個便於你掌握應用中React 組件動態的入口,因此更像是為打造其他實用庫而出現的基礎庫,比如在它之上可以開發出類似React DevTools 的實用工具或優化why-did-you-update!

//簡單改寫why-did-you-updatefunctionwhyDidYouUpdate(componentClass,componentInstance,lifecycleName,lifecycleArguments){if(lifecycleName==='componentDidUpdate'){const[props,state]=lifecycleArgumentsconstprev={props,state}constcur={props:componentInstance.props,state:componentInstance.state}deepCompareAndPrint(prev,cur)// why-did-you-update的深比較、輸出方法}}

通過它甚至可以實現polyfill react hooks!以下為我實現的概念版。

實現思路請看我的另一篇文章Enix:用HOC實現React hooks !

歡迎Star / issue !

PS: react-lifecycle-hooks 的名稱可能讓你想起近日大火的react useHooks 概念,但二者除了名字接近外沒有任何關係:-)

What do you think?

Written by marketer

blank

如何通過CRDT改進Vue應用? PostCSS作者Andrey告訴你

blank

編寫自己的SVG 圖標庫