需求是這樣的:有一個角色設置模塊,左側爲角色列表,右側爲權限樹。不一樣的角色會有不一樣的權限,切換角色的時候須要準確的顯示該角色擁有的權限,且有相關權限的用戶可對角色權限進行修改,即增長或刪除用戶的某一權限。git
首先,角色所擁有的權限樹是經過請求接口返回的對象數組的數據,每個權限擁有label、key、value和children。label、key、children對應tree組件裏面的title、key和children,value是一個布爾值,用來判斷當前權限是否被勾選(true爲被勾選)。大體數據結構以下:github
export const treeData = [ { title: "全局權限", key: "0", value: false, children: [ { title: "查看手機號", key: "1", value: false } ] }, { title: "帳號管理", key: "2", value: false, children: [ { title: "新增帳號", key: "3", value: true }, { title: "編輯帳號", key: "4", value: false }, { title: "刪除帳號", key: "5", value: false } ] } ]
在拿到數據以後,須要把數據轉換成樹形控件,由於存在子節點的渲染,因此天然而然也會想到遞歸的方法,這裏採用的是Ant Design文檔裏提供的方法:後端
// 組件樹形控件 子節點渲染 renderTreeNodes = data => data.map(item => { if (item.children) { return ( <TreeNode title={item.title} key={item.key}> {this.renderTreeNodes(item.children)} </TreeNode> ); } return <TreeNode title={item.title} key={item.key}></TreeNode>; });
至此,後端返回的數據能夠以樹形控件的形式展現:數組
前面說到,後端返回的每一個權限裏還有一個值是用來判斷當前權限是否被勾選。至關因而樹形控件默認選中的節點。我這裏的作法是先依次遍歷每一個節點,而後取出節點的value是true的值,返回一個數組,代碼以下:數據結構
// 權限樹獲取已勾選的節點的key值(value爲true) getCheckedKeys = (data) => { let arr = []; for (let i = 0;i < data.length;i++) { if (data[i].value) { arr.push(data[i].key) } if (data[i].children) { let res = this.getCheckedKeys(data[i].children) arr = [...arr, ...res] } } return arr; }
以上,已能夠將後端返回的數據以樹形結構展現出來,且能夠得到被勾選的節點的數組。
下一步工做就是要讓默認節點被勾選上,且能夠勾選或取消勾選任意節點。
首先想到的是受控組件的寫法:
受控組件是依賴於state的,即不論是默認值的賦值仍是值的改變都是要經過state的。但因爲需求裏的數據是從後端請求獲取的,在render
函數裏面是不容許使用setState
方法的,而在componentDidMount
這個生命週期函數裏還沒法獲取到接口返回的數據。因此只能考慮請求接口以後獲得數據再作處理。dispatch
這個函數有一個參數是回調函數,咱們能夠在請求接口的時候把接口返回的數據做爲回調函數的參數,這樣一來,咱們就能夠在請求接口的回調函數裏拿到咱們所想到的數據了,而且可使用setState
方法,render
函數代碼以下:函數
render() { return ( <Tree checkable onCheck={this.onCheck} checkedKeys={this.state.defaultCheckedKeys} > {this.renderTreeNodes(treeData)} </Tree> ); }
當勾選或取消勾選樹節點的時候,會觸發onCheck
事件。代碼以下:性能
onCheck = (checkedKeys) => { this.setState({ defaultCheckedKeys: checkedKeys }) }
除了受控組件的寫法,還能夠採用非受控組件。不過會存在必定的性能問題,具體的下面看代碼再解釋。this
render() { let defaultCheckedKeys = this.getCheckedKeys(treeData); return ( <Tree checkable onCheck={this.onCheck} defaultCheckedKeys={defaultCheckedKeys} key={this.treeIndex} > {this.renderTreeNodes(treeData)} </Tree> ); }
由於需求裏是不一樣角色切換的時候,要顯示對應的權限樹,也就是說,角色切換的時候樹是從新渲染的。因此在上面的代碼中,咱們給這個樹形控件再加一個屬性:key
。由於角色列表是一個數組,因此能夠把key
的值跟數組下標對應起來,這樣每次進行角色切換的時候,key
的值也會發生變化,樹形控件也會這個key
值的變化而從新渲染。可是,因爲樹形控件的從新渲染,若是一旦數據比較龐大的話,可能就會出現性能問題,在角色切換的時候,權限樹的顯示會有必定的延遲。
相比較而言,無論數據是否是從後端獲取的,受控組件的寫法更好一點,且不存在性能問題,可是受控組件是依賴於state的,因此值的獲取和改變都與state相關,這點須要注意,否則可能就會出現意想不到的問題。
demo連接spa