我最近在做后台管理系统时碰到了很突然的bug,有必要记录一下这些内容。
Bug:当我们去点击不同角色去设置其角色权限的时候,弹窗显示的默认勾选的角色权限都是一样的,实际上是不一样的。
解决方案:利用组件的componentWillReceiveProps()
,它会在接收到props
后先更新状态再render
渲染。
componentWillReceiveProps()
是React组件的一个很重要的生命周期函数。组件在初次渲染的时候不会执行该函数,只有当props
发生变化时才会执行该函数。它会在接收到props
后先更新状态再render
渲染。
该函数可以根据属性的变化,通过调用this.setState()
来更新我们的组件状态,在该函数中调用this.setState()
将不会引起第二次渲染。
部分关键代码如下:
父组件
......
export default class Role extends Component {
state = {
roles: [], //所有角色的列表
role: {}, //选中的role
};
constructor(props) {
super(props);
this.auth = React.createRef();
}
getRoles = async () => {
const result = await reqRoles();
if (result.status === 0) {
const roles = result.data;
this.setState({ roles });
} else {
message.error("获取角色失败!");
}
};
......
render(){
const { role } = this.state;
return (
......
<AuthForm ref={this.auth} role={role} /> //父组件传给AuthForm组件一个role对象
......
)
}
}
子组件
import React, { Component } from "react";
import { Form, Input, Tree } from "antd";
import PropTypes from "prop-types";
import menuList from "../../config/menuConfig";
const Item = Form.Item;
const { TreeNode } = Tree;
/* 设置角色权限的form组件 */
export default class AuthForm extends Component {
static propTypes = {
role: PropTypes.object, //子组件对接收的参数做类型限制
};
/* 根据传入角色的menu生成初始状态 */
constructor(props) {
super(props);
const { menus } = this.props.role; //从接收到的参数role中获取menus
this.state = { //更新这个组建的状态,这样就可以显示用户所点击的那个角色的权限内容了
checkedKeys: menus,
};
}
/* 选中某个node时的回调 */
onCheck = (checkedKeys) => {
console.log("onCheck", checkedKeys);
this.setState({ checkedKeys });
};
/* 获取角色权限树的节点,成后才才能显示本系统所有的权限内容,供管理员选择 */
getTreeNodes = (menuList) => {
return menuList.reduce((pre, item) => {
pre.push(
<TreeNode title={item.title} key={item.key}>
{item.children ? this.getTreeNodes(item.children) : null}
</TreeNode>
);
return pre;
}, []);
};
getMenus = () => this.state.checkedKeys;
componentWillMount() { //在组件挂载前获取到权限树,这样用户就可以看到权限树
this.treeNodes = this.getTreeNodes(menuList);
}
/* 根据新传入的role来更新checkedKeys状态
当组件接收到新的属性时自动调用 */
//也就是,当用户点击某个角色并点击“设置角色权限”按钮后,所弹出的弹框就会显示指定用户目前的角色权限情况,如果没有这个函数的处理,不论我们点击哪个角色,它们的角色权限列表显示的都是一样的
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps()", nextProps);
const menus = nextProps.role.menus;
this.setState({
checkedKeys: menus,
});
// this.state.checkedKeys = menus
}
/* 渲染 */
render() {
console.log("AuthForm render()");
const { role } = this.props;
const { checkedKeys } = this.state;
// const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 5 },
wrapperCol: { span: 16 },
};
return (
<Form>
<Item label="角色名称" {...formItemLayout}>
<Input value={role.name} disabled />
</Item>
<Tree
onCheck={this.onCheck}
checkable
defaultExpandAll={true}
checkedKeys={checkedKeys}
>
<TreeNode title="平台权限" key="all">
{this.treeNodes}
</TreeNode>
</Tree>
</Form>
);
}
}