前端如何根据ACL动态控制按钮显示?

宇文晓英 阅读 52

我们后端返回的用户权限是类似 {"user:delete": true, "post:edit": false} 这样的ACL结构。现在我想在React组件里根据这个权限决定“删除用户”按钮要不要渲染,但不确定怎么设计才不会让组件到处都是判断逻辑。

我试过在每个按钮外面包一层检查函数,但感觉很重复。有没有更优雅的方式?比如用高阶组件或者自定义Hook?

const hasPermission = (action) => {
  return userAcl[action] === true;
};

// 在组件里
{hasPermission('user:delete') && <button>删除用户</button>}
我来解答 赞 17 收藏
二维码
手机扫码查看
2 条解答
A. 彦会
A. 彦会 Lv1
自定义Hook是最简洁的方案,比HOC用起来舒服多了。

先定义一个usePermission Hook:

// hooks/usePermission.js
import { useMemo } from 'react';

export const usePermission = (acl) => {
const hasPermission = useMemo(() => {
return (action) => acl[action] === true;
}, [acl]);

return { hasPermission };
};

// 在组件里使用
const { hasPermission } = usePermission(userAcl);

return (
<div>
{hasPermission('user:delete') && <button>删除用户<button>}
{hasPermission('post:edit') && <button>编辑文章<button>}
</div>
);


这样每个组件只需要调用一次Hook,逻辑集中在一处。

如果你们项目里这种按钮特别多,可以再封装一个权限按钮组件:

// components/PermissionButton.jsx
export const PermissionButton = ({ action, acl, children, ...props }) => {
if (acl[action] !== true) return null;
return <button {...props}>{children}</button>;
};

// 用起来更简洁
return (
<div>
<PermissionButton action="user:delete" acl={userAcl}>删除用户</PermissionButton>
<PermissionButton action="post:edit" acl={userAcl}>编辑文章</PermissionButton>
</div>
);


第二种方式更干净,按钮的显示逻辑被彻底抽离出去了,组件代码里只剩业务相关的内容。

至于ACL的来源,要是从Context或者全局状态里取的,可以在Hook里直接读,不用每次都传参进去,那就更省事了。
点赞
2026-03-12 09:18
轩辕一诺
你现在的写法确实会让权限判断逻辑散落得到处都是,后期维护起来很痛苦。这个问题我之前也踩过坑,分享几个实用的方案。

最推荐的是封装一个权限组件,把判断逻辑收敛到一个地方:

import { createContext, useContext } from 'react';

const PermissionContext = createContext({});

export const PermissionProvider = ({ acl, children }) => {
return (

{children}

);
};

export const usePermission = () => {
const acl = useContext(PermissionContext);
return (action) => acl[action] === true;
};

// 权限控制组件
export const Authorized = ({ permission, fallback, children }) => {
const hasPermission = usePermission();

if (!permission) return children;

return hasPermission(permission) ? children : (fallback || null);
};


在应用入口挂载Provider:

function App() {
const [acl, setAcl] = useState({});

useEffect(() => {
fetchUserAcl().then(setAcl);
}, []);

return (



);
}


组件里用起来就很干净了:

import { Authorized } from './permission';

function UserList() {
return (





无权限}>



);
}


如果你嫌组件嵌套太深,也可以直接用Hook:

function UserList() {
const can = usePermission();

return (

{can('user:delete') && }

);
}


两种方式可以混着用,简单判断用Hook,复杂的或者需要fallback的场景用Authorized组件。

高阶组件的方式也可以,但现在Hooks更主流,HOC容易造成嵌套地狱,不太推荐了。

还有个坑要注意,权限数据一定要在组件渲染前准备好,不然会闪一下未授权的UI。可以在Provider外层加个loading状态,或者用Suspense处理。
点赞 2
2026-03-01 10:38