Skip to main content

useObserver

The useObserver hook integrates the Observer and Context, this can be used to subscribe listeners and receive notifications under certain constraints provided by the notification context.

Parameter

keyvaluerequireddescription
observerObserver instancetrueInstance of the class Observer
listenerFunctiontrueCallback function
contextscontext[]trueAn array of Context class instances. If a notification arrives that is not associated with any of the contexts in the array, the listener callback will not be triggered.

Example

import { useObserver } from 'hermes-io';

export function Counter() {
const [count, setCount] = useState(0);
const handleCounterNotification = (event) => {
// handle notification
};

useObserver({
contexts: [CounterContext],
observer: CounterObserver,
listener: handleCounterNotification,
});

return <h1>Counter: {count}</h1>;
}

generate hook (optional)

To simply things you can generate a custom hook by using hermes-io-cli

hermes-io-cli --root="./src" --hook="useCounter"

Fine grained updates

hermes-io allows smart and details updates by taking the responsibility of components communications, an observable architecture like this is an interesting alternative to: prop drilling, Redux, useContext.

Let's explore this concept by the following example:

// ./src/RenderTracker.jsx
function RenderTracker() {
// track re-renders using the `renderCount`
const renderCount = useRef(0);
renderCount.current++;
return <h2>Re render tracker: {renderCount.current}</h2>;
}

In the following structure when the parent re-renders all the children will re-render as well, if this behaviour is not the desired typically react provides techniques like memo


function Counter({ count }) {
return <h1>Count: {count}</h1>;
}

function App() {
const [count, setCount] = useState(0);
const increment = () => setCount((prevValue) => prevValue + 1);// increment value and update state
const decrement = () => setCount((prevValue) => prevValue - 1);// decrement value and update state

return (
<div>
<Counter count={count} />
<RenderTracker />
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

unoptimized

let's explore other way to optimize this component by moving the state inside Counter and handle the business logic within the incoming notifications:

export function Counter() {
const [count, setCount] = useState(0);
const handleCounterNotification = (event) => {
const { value = {} } = event;
const { type } = value;
if (type === INCREMENT) setCount((prevValue) => prevValue + 1);
if (type === DECREMENT) setCount((prevValue) => prevValue - 1);
};

useObserver({
contexts: [CounterContext],
observer: CounterObserver,
listener: handleCounterNotification,
});

return <h1>Counter: {count}</h1>;
}

optimized