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

Block Bindings: Fix passing bindings context to canUserEditValue #65599

Merged
Merged
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
53 changes: 24 additions & 29 deletions packages/block-editor/src/hooks/use-bindings-attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,7 @@ export const withBlockBindingSupport = createHigherOrderComponent(
const sources = useSelect( ( select ) =>
unlock( select( blocksStore ) ).getAllBlockBindingsSources()
);
const { name, clientId } = props;
const hasParentPattern = !! props.context[ 'pattern/overrides' ];
const hasPatternOverridesDefaultBinding =
props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ]
?.source === 'core/pattern-overrides';
const { name, clientId, context, setAttributes } = props;
const blockBindings = useMemo(
() =>
replacePatternOverrideDefaultBindings(
Expand All @@ -121,6 +117,7 @@ export const withBlockBindingSupport = createHigherOrderComponent(
// used purposely here to ensure `boundAttributes` is updated whenever
// there are attribute updates.
// `source.getValues` may also call a selector via `registry.select`.
const updatedContext = { ...context };
const boundAttributes = useSelect( () => {
if ( ! blockBindings ) {
return;
Expand All @@ -139,6 +136,11 @@ export const withBlockBindingSupport = createHigherOrderComponent(
continue;
}

// Populate context.
for ( const key of source.usesContext || [] ) {
Copy link
Member

Choose a reason for hiding this comment

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

With https://github.com/WordPress/gutenberg/pull/65599/files#r1772886078 applied, this can be refactored to:

let updatedContext = context;
if ( source.usesContext?.length ) {
    let updatedContext = { ...context };
    for ( const key of source.usesContext ) {
        updatedContext[ key ] = blockContext[ key ];
    }
}

updatedContext[ key ] = blockContext[ key ];
}

blockBindingsBySource.set( source, {
...blockBindingsBySource.get( source ),
[ attributeName ]: {
Expand All @@ -149,15 +151,6 @@ export const withBlockBindingSupport = createHigherOrderComponent(

if ( blockBindingsBySource.size ) {
for ( const [ source, bindings ] of blockBindingsBySource ) {
// Populate context.
const context = {};

if ( source.usesContext?.length ) {
for ( const key of source.usesContext ) {
context[ key ] = blockContext[ key ];
}
}

// Get values in batch if the source supports it.
let values = {};
if ( ! source.getValues ) {
Expand All @@ -168,7 +161,7 @@ export const withBlockBindingSupport = createHigherOrderComponent(
} else {
values = source.getValues( {
registry,
context,
context: updatedContext,
clientId,
bindings,
} );
Expand All @@ -190,9 +183,19 @@ export const withBlockBindingSupport = createHigherOrderComponent(
}

return attributes;
}, [ blockBindings, name, clientId, blockContext, registry, sources ] );

const { setAttributes } = props;
}, [
blockBindings,
name,
clientId,
updatedContext,
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be passing context, and the selector should return the updated context together with attributes:

const { boundAttributes, updatedContext } = useSelect( () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems moving updatedContext inside the useSelect triggers the same issue reported here where it throws the warning:

The 'useSelect' hook returns different values when called with the same state and parameters. This can lead to unnecessary rerenders.

I can take a look at the solutions suggested there, but I was wondering first: Would it be safe to directly modify the context prop? Instead of doing updatedContext[ key ] = blockContext[ key ]; do directly context[ key ] = blockContext[ key ];.

Copy link
Member

Choose a reason for hiding this comment

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

It's probably bad idea to mutate anything that React controls - props, context, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've started exploring moving the updatedContext to a useMemo call in this pull request.

registry,
sources,
] );

const hasParentPattern = !! updatedContext[ 'pattern/overrides' ];
const hasPatternOverridesDefaultBinding =
props.attributes.metadata?.bindings?.[ DEFAULT_ATTRIBUTE ]
?.source === 'core/pattern-overrides';

const _setAttributes = useCallback(
( nextAttributes ) => {
Expand Down Expand Up @@ -236,18 +239,9 @@ export const withBlockBindingSupport = createHigherOrderComponent(
source,
bindings,
] of blockBindingsBySource ) {
// Populate context.
const context = {};

if ( source.usesContext?.length ) {
for ( const key of source.usesContext ) {
context[ key ] = blockContext[ key ];
}
}

source.setValues( {
registry,
context,
context: updatedContext,
clientId,
bindings,
} );
Expand Down Expand Up @@ -277,7 +271,7 @@ export const withBlockBindingSupport = createHigherOrderComponent(
blockBindings,
name,
clientId,
blockContext,
updatedContext,
setAttributes,
sources,
hasPatternOverridesDefaultBinding,
Expand All @@ -291,6 +285,7 @@ export const withBlockBindingSupport = createHigherOrderComponent(
{ ...props }
attributes={ { ...props.attributes, ...boundAttributes } }
setAttributes={ _setAttributes }
context={ updatedContext }
/>
</>
);
Expand Down
Loading