<p>我在我的项目中遇到了一些钩子问题。这是一个用于检查用户权限并返回true或false的函数。</p>
<pre class="brush:php;toolbar:false;">import { useSelector } from "react-redux";
const CheckPermission = (module_key, permission_key) => {
const { user } = useSelector((state) => ({
user: state.auth.user,
}));
const rolePermissions = user?.role?.role_permissions ?? [];
const return_value = !!rolePermissions.find(
(p_list) =>
p_list.module?.key === module_key &&
p_list.permission?.key === permission_key
);
return return_value;
};
export default CheckPermission;</pre>
<p>然后我在我的侧边栏组件中使用它</p>
<pre class="brush:php;toolbar:false;">const renderMenu = (menu, key) => {
if (!CheckPermission(menu.moduleKey, menu.permissionKey)) {
return null;
}
return (
<Tooltip title={menu.name} placement="right" key={key}>
<NavLink
activeClassName={styles.active}
exact
className={styles.item}
to={menu.path}
>
<span className={styles.iconBox}>{menu.icon}</span>
<span className={styles.itemText}> {menu.name}</span>
</NavLink>
</Tooltip>
);
};
export default ({ collapse, onCollapse, isAdmin }) => {
const { user } = useSelector((state) => ({
user: state.auth.user,
}));
return (
<Layout.Sider
theme="light"
className={classnames(styles.sider, collapse ? styles.collapsed : "")}
collapsible
collapsed={collapse}
onCollapse={onCollapse}
width={collapse ? 64 : 264}
onBreakpoint={() => {}}
breakpoint="xl"
style={{
overflow: "auto",
height: "100vh",
position: "fixed",
left: 0,
top: 0,
paddingTop: "50px",
}}
>
<div className={styles.action}>
{user && user.read_only
? menus.map((menu, i) => {
if (menu.name === "Харилцагч") {
return renderMenu(menu, i);
} else {
return (
menu &&
menu.children &&
// eslint-disable-next-line array-callback-return
menu.children.map((submenu, j) => {
if (submenu.name === "QR данс") {
return (
<div key={i} className={styles.parentnav}>
{renderMenu(submenu, j)}
</div>
);
}
})
);
}
})
: menus.map((menu, i) => {
if (menu.path) {
return renderMenu(menu, i);
} else {
return (
<div key={i} className={styles.parentnav}>
{menu.name ? (
<div
className={`${styles.navlabel} ${styles.partentText}`}
>
{menu.name}
</div>
) : null}
{menu.children.map((submenu, j) => {
if (!submenu.path) return null;
if (isAdmin) {
return renderMenu(submenu, j);
} else {
return null;
}
})}
</div>
);
}
})}
</div>
</Layout.Sider>
);
};</pre>
<p>但是它抛出了"Error: Rendered more hooks than during the previous render.",我该如何在其他地方正确使用我的checkPermission函数。</p>
<p>我尝试在循环中使用checkPermission函数,结果是一样的。</p>
"错误:渲染时使用的hooks数量多于上一次渲染时的数量",通常发生在您使用React hooks(例如useSelector)的方式违反了hooks规则时。规则规定,hooks必须始终在函数组件的顶层调用,而不是在循环、条件或嵌套函数中调用。在您的代码中,您似乎在循环和条件中使用了CheckPermission函数。
// Sidebar.js import React from "react"; import { useSelector } from "react-redux"; import { NavLink, Tooltip } from "your-react-ui-library"; // 导入您的UI库 const Sidebar = ({ collapse, onCollapse, isAdmin, menus }) => { const { user } = useSelector((state) => ({ user: state.auth.user, })); // 将权限检查逻辑直接移入Sidebar组件 const checkPermission = (module_key, permission_key) => { const rolePermissions = user?.role?.role_permissions ?? []; return !!rolePermissions.find( (p_list) => p_list.module?.key === module_key && p_list.permission?.key === permission_key ); }; const renderMenu = (menu, key) => { // 使用本地的checkPermission函数进行权限检查 if ( !checkPermission(menu.moduleKey, menu.permissionKey) || (!isAdmin && !menu.path) ) { return null; } return ( <Tooltip title={menu.name} placement="right" key={key}> <NavLink activeClassName={styles.active} exact className={styles.item} to={menu.path} > <span className={styles.iconBox}>{menu.icon}</span> <span className={styles.itemText}> {menu.name}</span> </NavLink> </Tooltip> ); }; return ( <Layout.Sider // ... 其他属性和样式 ... > <div className={styles.action}> {user && user.read_only ? menus.map((menu, i) => { if (menu.name === "Харилцагч") { return renderMenu(menu, i); } else { return ( menu && menu.children && // eslint-disable-next-line array-callback-return menu.children.map((submenu, j) => { if (submenu.name === "QR данс") { return ( <div key={i} className={styles.parentnav}> {renderMenu(submenu, j)} </div> ); } }) ); } }) : menus.map((menu, i) => { if (menu.path) { return renderMenu(menu, i); } else { return ( <div key={i} className={styles.parentnav}> {menu.name ? ( <div className={`${styles.navlabel} ${styles.partentText}`} > {menu.name} </div> ) : null} {menu.children.map((submenu, j) => { if (!submenu.path) return null; if (isAdmin) { return renderMenu(submenu, j); } else { return null; } })} </div> ); } })} </div> </Layout.Sider> ); }; export default Sidebar;