最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

block editor - How do I listen for a change in an innerBlock child?

programmeradmin2浏览0评论

I've created a custom block that uses a WordPress core block as an innerBlock child; more specifically the core/embed block. What I'd like to do is listen for changes in the child block's attributes, so that I can respond to them in the parent block.

The custom block edit function returns the following:

return (
    <div { ...useBlockProps() } onChange={parentUpdate}>
        <InnerBlocks
            allowedBlocks={['core/embed']}
            template={EMBED_TEMPLATE}
            templateLock="all"
        ></InnerBlocks>
    </div>
);

And the parentUpdate function currently looks like:

const parentUpdate = () => {
    const thisBlock = select('core/editor').getBlocksByClientId(clientId)[0]
    const childBlock = thisBlock.innerBlocks[0]
    const videoURL = childBlock.attributes?.url
    console.log(videoURL)
}

The parentUpdate function fires whenever the url attribute in the child embed block changes but (perhaps unsurprisingly) it fires before the child event block updates, meaning I get the value prior to the change, not after.

How should I be approaching this, so that I can use the child attributes after the child block updates?

I've created a custom block that uses a WordPress core block as an innerBlock child; more specifically the core/embed block. What I'd like to do is listen for changes in the child block's attributes, so that I can respond to them in the parent block.

The custom block edit function returns the following:

return (
    <div { ...useBlockProps() } onChange={parentUpdate}>
        <InnerBlocks
            allowedBlocks={['core/embed']}
            template={EMBED_TEMPLATE}
            templateLock="all"
        ></InnerBlocks>
    </div>
);

And the parentUpdate function currently looks like:

const parentUpdate = () => {
    const thisBlock = select('core/editor').getBlocksByClientId(clientId)[0]
    const childBlock = thisBlock.innerBlocks[0]
    const videoURL = childBlock.attributes?.url
    console.log(videoURL)
}

The parentUpdate function fires whenever the url attribute in the child embed block changes but (perhaps unsurprisingly) it fires before the child event block updates, meaning I get the value prior to the change, not after.

How should I be approaching this, so that I can use the child attributes after the child block updates?

Share Improve this question edited Jan 26, 2022 at 10:56 verism asked Jan 26, 2022 at 10:09 verismverism 2161 silver badge15 bronze badges 7
  • onChange isn't a block related event, it's a DOM node related event, I do not believe you can do this via props and attributes in the component as that's not how block data works, <InnerBlocks> is not the source of data for inner blocks, it's just the mechanism by which they're displayed, it gets that data from elsewhere. What are you trying to implement that requires this? What is your block supposed to do? There's no context provided here so it's difficult to advise on the appropriate actions to take – Tom J Nowell Commented Jan 26, 2022 at 10:45
  • @TomJNowell Thanks for clarifying how innerBlock works (that was my assumption). What I'm trying to implement is a way to generally subscribe to attribute changes in child blocks, so that I may use those values in my own custom parent blocks—the specifics of what I need to do with those values are likely too broad to be of much use. – verism Commented Jan 26, 2022 at 10:59
  • let us be the judge of that, you might think they're irrelevant but I disagree, share them and then it'll be clear for all to see, the probability that there is a better way to do what you want to do, or that the approach isn't quite right is very high. I would go as far to say that needing to do this at all implies something has gone wrong somewhere, e.g. a big yellow flag was that at no point was useSelect considered. I would also say that all the things you would apply this to actually have very different solutions and this is the optimal solution for none of them – Tom J Nowell Commented Jan 26, 2022 at 13:36
  • @TomJNowell That's fair enough! Well in this particular instance, I'd like to use the url, supplied to the child embed block, to make an API call in my parent block to retrieve a video thumbnail. In Vue this can be done via refs, but I'm new to the React world and still getting to grips. – verism Commented Jan 26, 2022 at 14:18
  • I don't believe that innerblocks locked to embeds is the solution here, IMO you would be better using the OEmbed APIs and inputs that the embed uses to choose a suitable video in a singular block with no children – Tom J Nowell Commented Jan 26, 2022 at 15:29
 |  Show 2 more comments

1 Answer 1

Reset to default 2

You wouldn't, the need to do this is normally a code smell and a warning sign that you have done something wrong, or are trying to work against react and the way blocks are intended to work in some way.

However if you wanted to continue down the path in the wrong direction, you would rely on useSelect to acquire the information you wanted, directly accessing select isn't great and it also means you no longer get changes in your component.

But as I said, and as revealed in your comment, this is all a big hack to work around wanting to show embeds in a block, resulting in putting embed blocks in the inner blocks as children, forcing you to then implement this as a hack to get the information you need, an X Y problem. Don't do that.

Blocks should not depend on other blocks like this, they need to be composable like actual lego bricks. It's ok if two bricks were designed to work together, e.g. column and columns blocks, but it's not a good idea to repurpose a block for editor UI purposes like that.

Instead, read the edit component of the core/embed block at:

https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/embed/edit.js

It shows:

  • how to get a preview code and render it
  • handling loading spinners for when it's fetching the embed code
  • URL input for video links
  • sandboxes
  • embeddable vs unembeddable items

With these the URL would just become another prop on your block.

It may even be possible to instead adjust the embed block itself with additional attributes and components via filters to extend it if the goal of your task is to provide a modified UI for an embed. However the details of what your work is intended to implement are scarce.

发布评论

评论列表(0)

  1. 暂无评论