zouhir / preact-habitat

Zero configuration Preact widgets renderer in any host DOM
MIT License
518 stars 43 forks source link

Handling clicks and interactions - widget showing based on click #48

Open viperfx opened 4 years ago

viperfx commented 4 years ago

Is there any patterns we can follow to make the widget mount on load but show when the trigger element is clicked?

camsloanftc commented 3 years ago

Hey @viperfx, not sure if you sorted this out, but here is how I handled this:

In my consumer app/website, I added a data attribute to a button. So in my case it was:

<button data-my-widget-id="123">Launch widget</button>

I added an ID because I need to have multiple triggers on the page to do different things, but if you only need one trigger you could also just set this attribute to be something like below:

<button data-my-widget-start="true">Launch widget</button>

Then inside my widget I do something like below:

const [isVisible, setIsVisible] = useState(false)

useEffect(() => {
    function startTour() {
      setIsVisible(true)
    }

    const startButton = document.querySelector('[data-my-widget-start]') 
    if(!startButton) return;

    startButton.addEventListener('click', startTour)

    return () => {
      startButton.removeEventListener('click', startTour)
    }
  }, [])

return (
<div>
  {isVisible && (<YourComponent />)}
</div>
)

I'm not sure if this is the "right" way. I was initially trying to pass this in via the habitat props, but it looks like the props are not set up to observe changes after mounting, so you would need to work around that.

Would love to hear how you or others solved this.

viperfx commented 3 years ago

@camsloanftc Thanks for the suggestion. I am curious how did you use useEffect? Are you using functional components with preact?

Would you be able to show how the function and export is setup? and did you have to change anything with the habitat render?

camsloanftc commented 3 years ago

@viperfx that's correct. So I basically have all that inside a functional component and export it.

// components/App.js
function App() {
  const [isVisible, setIsVisible] = useState(false)

  useEffect(() => {
    function startTour() {
      setIsVisible(true)
    }

    const startButton = document.querySelector('[data-my-widget-start]')
    if (!startButton) return

    startButton.addEventListener('click', startTour)

    return () => {
      startButton.removeEventListener('click', startTour)
    }
  }, [])

  return <div>{isVisible && <YourComponent />}</div>
}

export default App

Then I import that into my index file with the habitat initialization as normal. No changes required there:

import habitat from 'preact-habitat'
import App from './components/App'

const _habitat = habitat(App)

_habitat.render({
  selector: '[data-widget-host="habitat"]',
  clean: true,
})
viperfx commented 3 years ago

@camsloanftc Thanks for the reply! I am finding that mounting is not as reliable as I thought it would be across different websites.

I came across your podcast and app, and was wondering if you are using this library for your app in production?

Would love to chat sometime about widgets - in Ontario too!

camsloanftc commented 3 years ago

Hey @viperfx - thats cool that you stumbled across the podcast!

I am actually not in production yet so I will need to look out for the issues you’re describing. If that ends up being the case I will have to look at alternatives or see about diagnosing the problem via logs.

Definitely up for widget chats! Feel free to reach out by dm on twitter. Would be great to connect.