Skip to content

garronej/powerhooks

Repository files navigation

A library of generic React hooks

This module is still under development. A real documentation website is coming.

Main hooks

useConstCallback

Believe it or not there is no valid reason to require user to pass in a dependency array to useCallback.

Demo playground to show you why it matters.

useCallbackFactory

To avoid re-rendering every list item component when the parent re-renders.

//Without powerhook:

todos.map(todo => <Todo todo={todo} onClick={(a, b) => onClick(todo, a, b)} />);

//With:

import { useCallbackFactory } from "powerhooks/useCallbackFactory";

//...

const onClickFactory = useCallbackFactory(([todo]: [string], [a, b]: [string, number]) =>
    onClick(todo, a, b)
);

todos.map(todo => <Todo todo={todo} onClick={onClickFactory(todo)} />);

Let's assume <TodoItem /> uses React.memo, in the example without powerhooks, every render of the parent the reference of onComplete changes.
useCallbackFactory on the other hand always returns the same function for a given todo: string.

useGlobalState

Create global state persistent across reloads that is accessible through out the entire app, and this without involving a provider.

NOTE: It makes uses of TypeScript's template literal types to return useIsDarkModeEnabled based on the name parameter ("isDarkModeEnabled").
How cool is that ?!

useIsDarkModeEnabled.ts

import { createUseGlobalState } from "powerhooks/useGlobalState";

export const { useIsDarkModeEnabled, evtIsDarkModeEnabled } = createUseGlobalState({
    name: "isDarkModeEnabled",
    initialState: window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches,
    doPersistAcrossReloads: true
});

MyComponent.tsx

import { useIsDarkModeEnabled } from "./useIsDarkModeEnabled";

export function MyComponent(){

  const { isDarkModeEnabled, setIsDarkModeEnabled }= useIsDarkModeEnabled();

  return (
    <div>
      <p>The dark mode is currently: {isDarkModeEnabled?"enabled":"disabled"}</p>
      <button onClick={()=> setIsDarkModeEnabled(!isDarkModeEnabled)}>
        Click to toggle dark mode
      <button>
    </dvi>
  );

}

Optionally, you can track your state an edit them outside of the react tree React but still trigger refresh when the state is changed.

import { evtIsDarkModeEnabled } from "./useIsDarkModeEnabled";

//After 4 seconds, enable dark mode, it will triggers re-renders of all the components
//that uses the state.
setTimeout(() => {
    evtIsDarkModeEnabled.state = true;
}, 4000);

//Print something in the console anytime the state changes:

evtIsDarkModeEnabled.attach(isDarkModeEnabled => {
    console.log(`idDarkModeEnabled changed, new value: ${isDarkModeEnabled}`);
});

For SSR (Next.js) use powerhook/useSsrGlobalState as showed in src/test/apps/ssr.

useDomRect

Measure rendered components in realtime.

import { useDomRect } from "powerhooks/useDomRect";

function MyComponent() {
    const { ref, domRect } = useDomRect();

    return (
        <>
            <div ref={ref}>
                This div is div size's dimensions <br />
                are determined by it's content
            </div>
            <div
                style={{
                    width: domRect.width,
                    height: domRect.height
                }}
            >
                This div is the same size as the first div
            </div>
        </>
    );
}

WARNING: Not yet compatible with SSR

Used by

Development

Start the test SPA

npx tsc -w
yarn start_spa