htmlstreamofficial / preline

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
https://preline.co
Other
4.9k stars 309 forks source link

Unable to use conditional render with Preline Js features #410

Closed luanfonsecap closed 2 months ago

luanfonsecap commented 4 months ago

Summary

Js features not work on components that conditionally render

Steps to Reproduce

I will use Accordion component to reproduce this bug, but any component that requires Preline Js to properly work's will fail.

  1. Setup Accordion in a React component;
  2. Import and render this component, work`s fine;
  3. Add a conditional rendering using a button to change some state and render's the Accordion when it's value's is true.
  4. Start the useState with true.
  5. Interact with Accordion, still working.
  6. Click on button to change state for false.
  7. Click again to to change state for true and component appears.
  8. Interact with Accordion, not working js features anymore.

Demo Link

https://codesandbox.io/p/devbox/preline-ui-k9nsvg?file=%2Fapp%2Fpage.tsx%3A19%2C17

Expected Behavior

Still working js features when need conditional rendering.

Actual Behavior

Js features stop working when component appears.

Screenshots

No response

ebraheemijaz commented 4 months ago

i noticed same behaviour for "modal" as well in order to handle it, i made the div as "hidden" and based on condition i'm removing/adding the "hidden" class.

another solution: use within component, that is rendered conditionaly.

useEffect(() => { window.HSStaticMethods.autoInit(); }, []);

langscot commented 3 months ago

Your PrelineScript component has a useEffect which calls autoInit() whenever the path name changes. This means any time you navigate, your components that re-render get re-initialized.

Routing is effectively "conditionally rendering" whichever page is defined for that pathname/route. So conditional rendering does work with Preline.

You need to do the same with your Accordion. You need to re-initialize your accordion every time your dependency for conditional rendering changes. In your case, this is your state bool. You could have a useEffect in your Accordion.tsx component which re-runs window.HSAccordion.autoInit() every render, or you could lift it up one level and have your useEffect in the page.tsx component and have state in your useEffect's dependency array.

Edit: Just read https://github.com/htmlstreamofficial/preline/issues/350#issuecomment-2139581724 which suggests this method could lead to a memory leak. You might be better off following @olegpix's example of using the JS constructor instead. Another option could be to call HSStaticMethods.cleanCollection() before your autoInit which effectively flushes out all your Preline instances before re-initializing them.

luanfonsecap commented 2 months ago

@langscot @ebraheemijaz Thank you, it helped a lot!