Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to understand useBlockSync #57074

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 6 additions & 20 deletions packages/block-editor/src/components/provider/use-block-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { useEffect, useRef } from '@wordpress/element';
import { useRegistry, useSelect } from '@wordpress/data';
import { useRegistry } from '@wordpress/data';
import { cloneBlock } from '@wordpress/blocks';

/**
Expand Down Expand Up @@ -81,16 +81,6 @@ export default function useBlockSync( {
} = registry.dispatch( blockEditorStore );
const { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } =
registry.select( blockEditorStore );
const isControlled = useSelect(
( select ) => {
return (
! clientId ||
select( blockEditorStore ).areInnerBlocksControlled( clientId )
);
},
[ clientId ]
);

const pendingChanges = useRef( { incoming: null, outgoing: [] } );
const subscribed = useRef( false );

Expand Down Expand Up @@ -135,6 +125,11 @@ export default function useBlockSync( {
setHasControlledInnerBlocks( clientId, false );
__unstableMarkNextChangeAsNotPersistent();
replaceInnerBlocks( clientId, [] );
// When the block becomes uncontrolled, it means its inner state has
// been reset we need to take the blocks again from the external
// value property.
pendingChanges.current.outgoing = [];
setControlledBlocks();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youknowriad I'm trying to understand if this change is fine or not. No tests are failing.

The areInnerBlocksControlled state is only set by the setHasControlledInnerBlocks action. And that action is only used twice in the code base, both in this file. It's only ever called once with false, which is here. So we can simply move the code here instead of using useSelect and a useEffect?

I'm not sure how to test, and I'm not sure if there's e2e test missing for this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, inner blocks are not controlled that often, so in terms of performance this is probably negligible. But still it's a bit simpler if possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function unsetControlledBlocks is only called when the block list is unmounted. I know for sure that there are some block that can change from "uncontrolled" to "controlled" while being mounted. So I think this change is probably breaking something.

That said reading the code, I wonder if we could just do this instead const isControlled = ! clientId && value !== undefined; to avoid the useSelect

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot how to trigger it but I think the "navigation" block can move from uncontrolled to controlled while being mounted. I'm also certain that there is another use-case but can't find it right now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subscription is not so important, it's only for controlled blocks anyway

} else {
resetBlocks( [] );
}
Expand Down Expand Up @@ -185,15 +180,6 @@ export default function useBlockSync( {
}
}, [ controlledBlocks, clientId ] );

useEffect( () => {
// When the block becomes uncontrolled, it means its inner state has been reset
// we need to take the blocks again from the external value property.
if ( ! isControlled ) {
pendingChanges.current.outgoing = [];
setControlledBlocks();
}
}, [ isControlled ] );

useEffect( () => {
const {
getSelectedBlocksInitialCaretPosition,
Expand Down
Loading