最先的時候,antd 的 Table
用起來是這樣的:javascript
const columns = [ { dataIndex: 'name', title: 'Name' }, { dataIndex: 'age', title: 'Age' }, { dataIndex: 'address', title: 'Address' } ] <Table columns={columns} data={data} />
只要把列定義和數據傳給 Table
組件,它就會幫你把表格渲染出來。咱們簡單實現一下上面的 Table
組件:java
class Table extends React.Component { render() { const { columns, data } = this.props; return ( <table> <thead> <tr> {columns.map(col => <th key={col.dataIndex}>{col.title}</th> )} </tr> </thead> <tbody> {data.map(item => ( <tr key={item.id}> {columns.map(col => <td key={col.dataIndex}>{item[col.dataIndex]}</td> )} </tr> ))} </tbody> </table> ); } }
後來,有人就以爲這樣寫不夠 React 啊,我想要用 JSX 來定義列啊。react
好吧,那咱們把上面的 Table
改造一下,容許用 JSX 的方式。git
const Column = () => {}; class Table extends React.Component { static Column = Column; render() { const { children, columns, data } = this.props; this.columns = columns || React.Children.map(children, (child) => ({ dataIndex: child.props.dataIndex, title: child.props.title, })) return ( <table> <thead> <tr> {this.columns.map(col => <th key={col.dataIndex}>{col.title}</th> )} </tr> </thead> <tbody> {data.map(item => ( <tr key={item.id}> {this.columns.map(col => <td key={col.dataIndex}>{item[col.dataIndex]}</td> )} </tr> ))} </tbody> </table> ); } }
這裏咱們定義了一個什麼都不幹的 Column
組件,而後 Table
組件經過遍歷本身的子元素來把列信息讀出來。這樣就實現 issue 裏要求的功能,很是簡單。github
但是,過了段時間,又有人不滿意了。antd
既然如今支持 JSX 的方式定義列了,那我就想封裝本身的 XxxColumn
組件啊。可是從咱們上面的實現能夠看到,Table
是直接從本身的子元素上讀取列信息的,如今若是 Column
組件被封裝起來,咱們就讀不到 Column
上的信息了。this
這個問題,一直沒有很好的解法。可是,就在昨天,隨着 React 16.1 的發佈,React Team 還發布了兩個實驗性的包 react-reconciler
和 react-call-return
。其中 react-reconciler
用來實現自定義的 renderer,此處暫且不表。而 react-call-return
這個初看名字徹底不知道什麼東西的包,就能夠解決上面的問題。spa
react-call-return
提供了兩個方法 unstable_createReturn
和 unstable_createCall
。設計
咱們先來用這兩個方法從新實現一下上面的 Table
組件,再來看咱們的問題是怎麼被解決的。code
const Column = (props) => unstable_createReturn(props); class Table extends React.Component { static Column = Column; render() { const { children, data } = this.props; return ( <table> <thead> <tr> {unstable_createCall(children, (props, columns) => ( columns.map(col => ( <th key={col.dataIndex}>{col.title}</th> )) ), this.props)} </tr> </thead> <tbody> {data.map(item => ( <tr key={item.id}> {unstable_createCall(children, (props, columns) => ( columns.map(col => ( <td key={col.dataIndex}>{item[col.dataIndex]}</td> )) ), this.props)} </tr> ))} </tbody> </table> ); } }
能夠看到,Column
組件再也不什麼都不作了,它用 unstable_createReturn
建立了一個 return
,return 的內容,就是它本身的 props
。而後咱們在 Table
裏調用 unstable_createCall
, 這個方法的第一個參數是 Table
的子元素,第二個參數是一個 handler 方法,,第三個參數是 Table
的 props
。由於 Table
的子元素,也就是 Column
返回了一個 return
,因此當咱們 call
這些 return
的時候,React 會把 Column
return 的結果傳給咱們的 handler 方法,大概就是這個過程 handler(props, children.map((c => c.call() )))
。這樣咱們就拿到了 Column
上的 props
,即便 Column
被封裝起來了也不會有問題。
react-call-return 的出現,讓咱們在組件設計上有了更多的可能性,JSX 再也不須要映射 DOM,而是能夠直接來表達數據。
以上全部演示代碼,能夠在這裏找到 https://github.com/yesmeck/neotable