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

Children of custom element gets rendered twice #32

Closed
donpark opened this issue May 16, 2020 · 8 comments
Closed

Children of custom element gets rendered twice #32

donpark opened this issue May 16, 2020 · 8 comments

Comments

@donpark
Copy link

donpark commented May 16, 2020

This may be related to #18 but when custom element renders its children property like this:

const Greeting = ({ children, name = "World" }) => (
  <h1 id="hello">
    <p>Hello {name}!</p>
    {children}
  </h1>
);

They are rendered twice in two different styles (shadow and document?) like this:

screenshot_1031

See: https://codesandbox.io/s/preact-custom-element-rendering-content-issue-g7ko9

I also noticed in some test cases where the custom element, not just children, gets rendered twice when some elements are added. When traced in such cases, children property included the root element (direct children of shadowRoot) instead of the children from HTML.

Looking at preact-custom-element source code, I'm having difficulty finding where children parameter comes from. In my 'bare-metal' custom element implementation, I capture children via a MutationObserver like this:

    connectedCallback() {
        const shadowRoot = this.shadowRoot;
        var observer = new MutationObserver(function (mutations) {
            mutations.forEach((mutation) => {
                for (const child of mutation.addedNodes) {
                    shadowRoot.querySelector('.info').appendChild(child)
                }
            })
        })
        observer.observe(this, { childList: true })
    }
@donpark
Copy link
Author

donpark commented May 17, 2020

nvm. It looks like adding an unnamed slot fixes the problem. There were some odd behaviors while I was tinkering with the fix but seemingly unrelated changes made them unreproducible.
Closing.

@donpark donpark closed this as completed May 17, 2020
@mknet
Copy link

mknet commented Jun 4, 2020

@donpark Could publish a short example showing your solution with the unnamed slot?
I'd appreciate it! Thx!

@donpark
Copy link
Author

donpark commented Jun 4, 2020

With HTML emitted using PHP like this:

    <div class="<?php echo $blockSpec['outerClassName']; ?>">
        <talk-section id="talk-block-<?php echo $attributes['blockId']; ?>" display="gutenberg">
            <div class="talk-content">
                <?php echo $inner_blocks; ?>
            </div>
            <script type="application/json" class="talk-data">
                <?php echo $data; ?>
            </script>
        </talk-section>
    </div>

And custom element talk-section's renderer looks like this:

        return [
            <link rel="stylesheet" href="/wp-content/plugins/talk/elements/index.css" media="all"></link>,
            <div ref={this.sectionRef} className="talk-section" style={sectionStyle}>
                <slot />
                <TalkAudio
                    autoLevel={autoLevel}
                    autoPlay={autoPlay}
                    recording={recording}
                    audioRef={this.audioRef}
                ></TalkAudio>
                {chyronComponent}
            </div>,
        ];

DOM will look like this:
screenshot_1059

Child elements of the custom element get mapped as children of the slot element, allowing the custom element to position them anywhere within its hierarchy.

@mbohgard
Copy link

@donpark Hi. I'm having the same issue. Can't get it to work somehow with the unnamed slot. Can you alter your codesandbox sample to actually solve the issue? Thank you!

@donpark
Copy link
Author

donpark commented Aug 27, 2020

@mbohgard here is the fixed sample
https://codesandbox.io/s/preact-custom-element-rendering-content-issue-forked-38xpc?file=/src/index.js

In short,

  1. Add an unnamed <slot />
  2. Remove {children}

@marvinhagemeister
Copy link
Member

@mbohgard @donpark There is no need to use an unnamed <slot>-node instead of just passing {children}. Instead, to resolve this issue one only needs to update to the latest version of preact-custom-element. At the time of the writing this is 4.1.0. See this codesandbox 👍

@mbohgard
Copy link

@marvinhagemeister Thanks! I had issues with that tho as described here.

@mufaddalmw
Copy link

@mbohgard @donpark There is no need to use an unnamed <slot>-node instead of just passing {children}. Instead, to resolve this issue one only needs to update to the latest version of preact-custom-element. At the time of the writing this is 4.1.0. See this codesandbox 👍

How to achieve same behavior when shadow: false is applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants