Effect Helper

When using state data you notice that only the part of the template dependent on the state will update with changes.

For those situations you could want to perform "side effects", meaning, you want other part of the template to change with the state change.

That is when the effect helper comes in. To help you perform these side effects directly in the template.

const doubleCount = () => count() * 2;

const counter = html`
  <p>${count}</p>

  <!-- Also display count doubled whenever count changes -->
  <p>${effect(count, doubleCount)}</p>
`;

Above example shows a simple example of how to perform a side effect to display double of count whenever count changes.

Bellow example shows that using effect we can react to something like the activeTab state change to dynamically get content for the tab and render it.

type Tab = 'home' | 'about' | 'contact';

const tabContent: Record<Tab, HTMLTemplate> = {
  home: html`<h1>Welcome</h1>`,
  contact: html`<p>Tell us what you think</p>`,
  about: html`<p>We are here to help you</p>`,
}

const [activeTab, setActiveTab] = state<Tab>("home");

const app = html`
  <h1>Tab Example</h1>
  <ul>
    <li 
      class.active="${is(activeTab, 'home')}" 
      onclick="${() => setActiveTab('home')}">
      Home
    </li>
    <li 
      class.active="${is(activeTab, 'about')}"
      onclick="${() => setActiveTab('about')}">
      About
    </li>
    <li 
      class.active="${is(activeTab, 'contact')}"
      onclick="${() => setActiveTab('contact')}">
      Contact
    </li>
  </ul>
  ${effect(activeTab, () => tabContent[activeTab()])}
`;

app.render(document.body)

Effect format

The effect helper takes comma-separated states and the last argument must be the action to take or, the "thing" you need to be returned or rendered.

effect(STATE, ...STATE, SIDE_EFFECT_ACTION)

// react to 'activeTab' and 'currentPath' state changes 
// to load content by calling 'contentLoader'
effect(activeTab, currentPath, contentLoader)