Hooks: useEffect
Used to run a side-effect when the component rerenders or when a dependency changes. To run your side-effect only when the component rerenders, only pass in your side-effect function and nothing else:
import { component, html, useState, useEffect } from 'haunted';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
// on every render, a new number will be in the title
document.title = `A random number ${Math.random()}`;
});
return html`
<header>${document.title ?? 'Click the Button'}</header>
<div id="count">${count}</div>
<button type="button" @click=${() => setCount(count + 1)}>
Cause rerender
</button>
`;
}
customElements.define('use-effect', component(Counter));
<script type="module" src="use-effect.js"></script>
<use-effect></use-effect>
Dependencies
What happens when your code begins to rely on dependencies that can change (state, refs, props)? We no longer want it to rerun on every rerender so we need to ensure that the code we're running, or its result, doesn't become stale. To do this, you should always state all of the dependencies you're using in an array as the second argument to useEffect
:
const [name, setName] = useState('Dracula');
useEffect(() => {
// This only occurs when `name` changes and on the initial render.
document.title = `Hello ${name}`;
}, [name]);
A dependency is anything that your side-effect relies on that can change between renders (e.g. state, refs, props). This does not include setName
or other setters from useState
because they will never change between renders.
What if I want to run the side-effect on mount?
Generally, you won't want to do this but rather make sure you're actually listing all of your dependencies in the dependency array. If you don't have any dependencies then your code will run on mount and clean up on unmount.
Here is an example of only running an effect once as opposed to every rerender:
useEffect(() => {
document.title = 'I will stay like this until someone changes me';
}, []); // note that you must pass the empty array
Cleaning up side-effects
Since effects are used for side-effectual things and might run many times in the lifecycle of a component, useEffect
supports returning a teardown function.
An example of when you might use this is if you are setting up an event listener:
const [name, setName] = useState('Wolf Man');
useEffect(() => {
function updateNameFromWorker(event) {
setName(event.data);
}
worker.addEventListener('message', updateNameFromWorker);
return () => {
worker.removeEventListener('message', updateNameFromWorker);
};
}, []); // note that it is safe to exclude `setName` from the dependencies because it will never change
API
setEffects
Parameters
state
cb
useEffect
Parameters
effect
() => void
callback function that runs each time dependencies change
dependencies
unknown[]
list of dependencies to the effect
Returns
void
Exports
import { setEffects, useEffect } from 'haunted/lib/use-effect';