您可以通过多种方式做到这一点。如果您想保持类似的流程(使用访问包装器),那么您应该让包装器本身处理单击以有条件地呈现按钮。
这是一种简单的方法来做到这一点(如上所述,有很多方法可以做到这一点,如果您想要不同的版本,请告诉我):
import React from "react";
const AccessControl = ({ hasAccess, handleClick, children }) => {
const handleButtonClick = () => {
if (hasAccess) {
handleClick();
} else {
console.log('Access denied');
}
};
return (
<div>
{hasAccess ? (
children
) : (
<button disabled onClick={handleButtonClick}>
Access Denied
</button>
)}
</div>
);
};
export default AccessControl;
用法:
<AccessControl hasAccess={checkUserAccess()}>
<UltimateButton
btntext="+ New document"
classes="btn-primary"
handleClick={create_new_doc}
/>
</AccessControl>
看来您克隆子组件的想法是正确的。
克隆子组件并重新注入一个“装饰”的
handleClick
属性,该属性首先调用 checkUserAccess
,如果此函数返回 true 或确认用户具有访问权限,则它将调用最初传递的 handleClick
回调。
示例:
const AccessControl = ({ children }) => {
const checkUserAccess = () => {
// Compute hasAccess
console.log(hasAccess ? "Access allowed" : "Access denied");
return hasAccess;
};
return Children.map(children, (child) =>
cloneElement(child, {
handleClick: (e) => checkUserAccess() && child.props.handleClick(e)
})
);
};
const AccessControl = ({ children, hasAccess }) => {
const checkUserAccess = () => {
console.log(hasAccess ? "Access allowed" : "Access denied");
return hasAccess;
};
return React.Children.map(children, (child) =>
React.cloneElement(child, {
handleClick: (e) => checkUserAccess() && child.props.handleClick(e)
})
);
};
const UltimateButton = ({ btntext, handleClick }) => (
<button type="button" onClick={handleClick}>
{btntext}
</button>
);
const App = () => {
const create_new_doc = () => console.log("create_new_doc");
return (
<div className="App">
<UltimateButton
btntext="No Access Control + New document"
classes="btn-primary"
handleClick={create_new_doc}
/>
<AccessControl hasAccess>
<UltimateButton
btntext="Has access + New document"
classes="btn-primary"
handleClick={create_new_doc}
/>
</AccessControl>
<AccessControl>
<UltimateButton
btntext="No access + New document"
classes="btn-primary"
handleClick={create_new_doc}
/>
</AccessControl>
</div>
);
};
const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root" />