Cannot use useSelector in the "restricted" function of a Block
Describe the bug
I'm trying to make only a user with a Manager role add a certain block. I tried to restrict the block with the restricted function:
https://6.docs.plone.org/volto/development/how-to-restrict-blocks.html
To get the user I used the userSelector inside the restricted function. So when I click on a Text block when editing content, I get the error:
Uncaught TypeError: Cannot read properties of undefined (reading 'length')
at areHookInputsEqual (react-dom.development.js:16249:1)
at updateEffectImpl (react-dom.development.js:17078:1)
at updateEffect (react-dom.development.js:17098:1)
at Object.useEffect (react-dom.development.js:17862:1)
at Object.useEffect (react.development.js:1634:1)
at useIsMounted (SlashMenu.jsx:24:1)
at PersistentSlashMenu (SlashMenu.jsx:161:1)
at renderWithHooks (react-dom.development.js:16305:1)
at updateFunctionComponent (react-dom.development.js:19588:1)
at beginWork (react-dom.development.js:21601:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
at invokeGuardedCallback (react-dom.development.js:4277:1)
at beginWork$1 (react-dom.development.js:27451:1)
at performUnitOfWork (react-dom.development.js:26557:1)
at workLoopSync (react-dom.development.js:26466:1)
at renderRootSync (react-dom.development.js:26434:1)
at performSyncWorkOnRoot (react-dom.development.js:26085:1)
at flushSyncCallbacks (react-dom.development.js:12042:1)
at react-dom.development.js:25651:1
Analyzing the error, I found that it occurs because the useSelector call occurs inside a useMemo, which is not recommended. The useMemo in question is this one:
https://github.com/plone/volto/blob/0edcd8083afee783a6463a14b18d0f712cf7c25b/packages/volto-slate/src/blocks/Text/SlashMenu.jsx#L119
And the call to the restricted function, which calls useSelector occurs here:
https://github.com/plone/volto/blob/0edcd8083afee783a6463a14b18d0f712cf7c25b/packages/volto-slate/src/blocks/Text/SlashMenu.jsx#L125
I believe it is not a good idea to remove useMemo. So what can be done? Is there any other way to restrict adding a block only to Manager?
This is related to #5137
To Reproduce Steps to reproduce the behavior:
- To make reproduction easier, we will do it in a block of Volto itself.
- In the file:
https://github.com/plone/volto/blob/main/packages/volto/src/config/Blocks.jsx
import useSelector:
import { useSelector } from 'react-redux';
- Replace the
restrictedin the HTML block:
https://github.com/plone/volto/blob/a4965580f3d443d1b102344d2fcb9d8ed1728ec7/packages/volto/src/config/Blocks.jsx#L386
to:
restricted: () => {
useSelector((state) => state.users?.user);
},
- Add a Document and click on an empty Text block.
Expected behavior There should be no error when clicking on a Text block.
Software (please complete the following information):
Volto 18.0.0-alpha.42 Plone 6.0.11 plone.restapi 9.7.0 CMF 3.5 Zope 5.9 Python 3.11.9 (main, May 14 2024, 08:32:26) [GCC 10.2.1 20210110] PIL 9.5.0 (Pillow)
The option I see would be to get the user in the PersistentSlashMenu component itself, and pass it to the restricted function. Would that be acceptable?
The option I see would be to get the user in the PersistentSlashMenu component itself, and pass it to the restricted function. Would that be acceptable?
@wesleybl That sounds like a pretty good solution to me. It's backwards compatible with existing implementations of restricted and sounds generally useful.