這陣子寫React的components,常常很快就完成了期待的效果。
但是總覺得沒有重用性、無法從application獨立出來。
我想將元件中可重用的部份獨立出來,成為基本元件,接著針對application另寫元件去擴充這些基本元件。
有辦法讓一個component去繼承另一個component嗎?似乎不行。
我首先在開發React-Lightbox時遇到了上述問題。
我想製作一個Lightbox效果的plugin,提供Lightbox、LightboxTrigger、LightboxModal三個component,讓developer自訂觸發Lightbox的按鈕、Lightbox框框內的內容。
用法類似這樣:
React.renderComponent(, document.getElementById('react-canvas') );
範例中的ToggleButton跟MyPanel是由developer自訂。
該怎麼達成這個效果呢?
毫無頭緒之下,我寫出像這樣的code:
for (j in this.props){ if (j !== 'children'){ this.props.children.props[j] = this.props[j]; } }
for(i in this.props.children){ this.props.children[i].props.openLightbox = this.openLightbox; this.props.children[i].props.closeLightbox = this.closeLightbox; this.props.children[i].props.setLightboxState = this.setLightboxState; for (j in this.state){ this.props.children[i].props[j] = this.state[j]; } }
簡單地說,就是硬著頭皮傳遞某些props、達到類似「繼承」的「擴充」效果。
眼前的問題解決了,但是tomchentw指出這樣寫法的問題所在(感謝指點):
‘At my first glance it looks pretty magic.’
該怎麼辦呢?
我最後終於在這篇SO的問答找到了一線希望:
由component去wrap住基本component來達到擴充的效果,然後利用JSX Spread Attributes的幫助來傳遞props。
利用這些,我開發出了第二個React的plugin:Tag Manager
所謂「使用者自訂component去擴充基本component」的code,大概長這樣:
/** @jsx React.DOM */ var MyCustomTagManager = React.createClass({ addTagCallback: function(tagName, setStateCallback){ alert('Add a tag! Maybe you should send an ajax!'); setStateCallback({id: 99, name: tagName}); }, removeTagCallback: function(tag){ alert('Remove a tag! Maybe you should send an ajax!'); }, render: function(){ return() } });
反省
再看一眼,發現前面的寫法跟後面的寫法其實都是「用component去包住component」,意義上其實類似。
(都是叫composition?我理論沒學好,對專有名詞不熟@@”)
後面的寫法看起來更explicit了,maintainability跟readability應該也更高了吧?
您覺得呢?