需求是这样的:有一个角色设置模块,左侧为角色列表,右侧为权限树。不一样的角色会有不一样的权限,切换角色的时候须要准确的显示该角色拥有的权限,且有相关权限的用户可对角色权限进行修改,即增长或删除用户的某一权限。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