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

multiple instance on the same page #204

Open
clodoveo opened this issue Oct 17, 2024 · 11 comments
Open

multiple instance on the same page #204

clodoveo opened this issue Oct 17, 2024 · 11 comments

Comments

@clodoveo
Copy link

I'm trying to develop a widget that ideally should be instantiated multiple times on the same page. However, it is only being rendered for the first one in the list. Is it possible to have more than one with the same name but for example different IDs?

@bmomberger-bitovi
Copy link
Contributor

bmomberger-bitovi commented Dec 6, 2024

Hi @clodoveo,

Can you show me some example code? I've definitely done experiments in the past with multiple instances of the same component and didn't have this problem, so I might be able to find the root of the problem if I see how you're using it.

@subramanian-iouring
Copy link

subramanian-iouring commented Jan 10, 2025

@bmomberger-bitovi
While using same web component in html with different params, facing issues like collapse the data params between web components.

<div class="menu1"> 
  <web-app name="sam" age="32"></web-app>
</div>
<div class="menu2">
  <web-app name="jack"></web-app>
</div>

From above code, we are allowing any one of div to DOM, while showing 1st div, 2nd div is not DOM.
So when we try to remove 1st div and append 2nd div in DOM. we are getting age props here too.

@bmomberger-bitovi
Copy link
Contributor

What library are you using to remove and append these divs? Is it one with a virtual DOM? It's possible that the library is reusing the same web-app element for efficiency, which would lead to the condition you're describing.

@subramanian-iouring
Copy link

@bmomberger-bitovi
Actually not using any library, based on boolean i tried to show the web-app in react.

@bmomberger-bitovi
Copy link
Contributor

bmomberger-bitovi commented Jan 13, 2025

You tried to show the web-app in React? React is a library that uses virtual DOM just like I described above.

Here, this pen shows how the instance swap with regular DOM manipulation does not leave a stale value for age: https://codepen.io/bmomberger-bitovi/pen/WbezqzM

Edit: If you see this problem in React, try generating a unique key for every instance of <web-app> that you show or hide. I don't have the bandwidth to test this right now, but it is the sensible first thing to try.

@subramanian-iouring
Copy link

@bmomberger-bitovi
Am using redux for state management with react, and that is web component.
when i open r2wc element in DOM and we store something in redux and removed the r2wc web element in DOM.
Again when i open r2wc component in DOM. is existing redux value will persist?

Am facing issue in this scenario. the redux values are persists.

@bmomberger-bitovi
Copy link
Contributor

@subramanian-iouring When you initialize your redux Provider, where is your store coming from?

If it's always the same store object being passed to the redux Provder, then it will have the same values even if you remove the React root and re-create it.

@subramanian-iouring
Copy link

subramanian-iouring commented Jan 16, 2025

@bmomberger-bitovi

Here, is the exact code. which am using redux Provider. is any other way to resolve this issue?

const AppWrapper = (props: any) => {
    const { children } = props;

    const [
        domRef, setDomRef
    ] = useState<HTMLStyleElement>();

    const cache = useMemo(() => {
        if (domRef)
            return createCache({ key: "css", prepend: true, container: domRef });
        return null;
    }, [
        domRef
    ]);

    const getRef = useCallback((ref: HTMLStyleElement | null) => {
        if (ref)
            setDomRef(ref);
    }, [
    ]);

    return <StyledEngineProvider injectFirst>
        <Provider store={store}>
            <style ref={getRef}></style>
            <link rel="stylesheet" href={`${AppSettings.publicUrl?.trim()}/static/css/nxtoption-sdk.css`} />

            {cache !== null ? <CacheProvider value={cache}> {children} </CacheProvider> : null}
        </Provider>
    </StyledEngineProvider>;
};

const AppContainer = (props: any) => {
    if (isEmpty(props))
        return <div>Invalid payload</div>;

    return <AppWrapper>
        {
            {
                [ APP_MODE.HOME ]: <App {...props} />,
                [ APP_MODE.ANALYZE ]: <App {...props} isAnalyze={true} />
            }[ props.mode ]
        }
    </AppWrapper>;
};

const WebAppComponent = r2wc(AppContainer, {
    shadow: "open",
    props: {
        payload: "string",
        eventcallback: "function"
    }
});

class WebApp extends WebAppComponent {
    constructor() {
        super();
        loadFont("NxtOption-Icon-Font", `${AppSettings.publicUrl?.trim()}/assets/icons/nxtoption.ttf`);
        loadFont("NxtOption-Regular", `${AppSettings.publicUrl?.trim()}/assets/fonts/nxtoption-regular.woff2`);
    }

    connectedCallback() {
        console.log("connectedCallback");
    }

    disconnectedCallback() {
        console.log("disconnectedCallback");
    }
}

customElements.define("web-app", WebApp);

// Using web-app in another react application

<div class="menu1"> 
  <web-app mode="home"></web-app>
</div>
<div class="menu2">
  <web-app mode="analyze" {...props} ></web-app>
</div>

@bmomberger-bitovi
Copy link
Contributor

Your code shows <Provider store={store}> but doesn't have any other reference to store. I am assuming that it's imported from another module.

What I would do instead is to have that module export a function like getInitialStore() that returns the initial state of your redux store, and then in your AppWrapper:

const [store] = useState(getInitialStore());

useState() is used here because it will not revert to the initial store on component update, only on component mount.

@subramanian-iouring
Copy link

subramanian-iouring commented Jan 22, 2025

@bmomberger-bitovi
Thanks for support.

Need some clarification on below.

When using web component, how to remove the web-component completely in browser/DOM.

<script>
var age = 32;

function changeAge(value) {
    age = value;
}
</script>

<web-app name="sam" age={age} callbackfunc="changeAge"></web-app>

I changed the age using callback function and if i delete the web component like below, getting old values when i open/append web-app again in DOM.

const element = document.getElementsByTagName("web-app")[0];
if (element) 
    element.remove();

so the query is how to remove the entire values/store when i remove the <web-app> from DOM and it should be fresh and new <web-app> when i open again.

Actually where should we have to remove the things? in r2wc web component application or the application where we using web component as element ?

@bmomberger-bitovi
Copy link
Contributor

bmomberger-bitovi commented Jan 22, 2025

age in a script like that creates a global variable. When you run changeAge() you're changing a global value that exists independently of whether the <web-app> component exists or not.

You can see this by examining window.age in the browser console.

if you want values to be fresh and reset every time you create a web-app you should have something like:

function createStore() {
  let age = 32:
  const expando = Math.floor(Math.random * 100000);
  window[`changeAge${expando}`] = newAge => age = newAge;
  return {
   get age() { return age; },
   callbackfunc: `changeAge${expando}`
 };
}

<web-app name="sam" {...createStore()} />

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

3 participants