1.0.0 • Published 2 years ago

@kmpizmad/react-hooks-util v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Introduction

Utility library for common React hooks

The idea was to create a library that contains common functionalities abstracted into hooks rather than implementing them everytime in every project.

Guidelines

Lifecycle hooks

useMountEffect

type: (effect: React.EffectCallback) => void

Represents the componentDidMount method from React class components

const DidMountComponent = () => {
  const [value, setValue] = React.useState<number>(0);
  const [dependency, setDependency] = React.useState<number>(0);

  useMountEffect(() => {
    setValue(dependency + 1);
  });

  return (
    <div>
      <div data-testid="test-value">{value}</div>
      <button onClick={() => setDependency(dependency + 1)}>Click Me!</button>
    </div>
  );
};

useUnmountEffect

type: (effect: React.EffectCallback, deps: React.DependencyList = []) => void

Represents the componentWillUnmount method from React class components

const WillUnmountComponent = () => {
  const [value, setValue] = React.useState<number>(0);

  useUnmountEffect(() => {
    setValue(-1);
  });

  return <div>{value}</div>;
};

useUpdateEffect

type: (effect: React.EffectCallback, deps?: React.DependencyList) => void

Renders whenever a dependency changes or if provided without a dependency list, renders on any change. Avoid providing an empty dependency list

const DidUpdateComponent = () => {
  const [value, setValue] = React.useState<number>(0);
  const [dependency, setDependency] = React.useState<number>(0);

  useUpdateEffect(() => {
    setValue(dependency);
  }, [dependency]);

  return (
    <div>
      <div>{value}</div>
      <button onClick={() => setDependency(dependency + 1)}>Click Me!</button>
    </div>
  );
};

usePrevState

type: (state: PrevState) => PrevState

getSnapshotBeforeUpdate, componentShouldUpdate and componentWillRecieveProps combined in one. Captures the previous state based on the input object

const PrevStateComponent = () => {
  const [dependency, setDependency] = React.useState<number>(0);
  const prevState = usePrevState({ dependency });

  return (
    <div>
      <div>{prevState?.dependency || '-1'}</div>
      <button onClick={() => setDependency(dependency + 1)}>Click Me!</button>
    </div>
  );
};

DOM hooks

useToggle

type: (initialValue?: boolean) => ToggleObject

Toggles state between true and false

const ToggleComponent = (props: { initialValue?: boolean }) => {
  const { value, toggle } = useToggle(props.initialValue);
  return (
    <div>
      <div>{value.toString()}</div>
      <button onClick={() => toggle()}>Click Me!</button>
    </div>
  );
};

useEventListener

type: (type: keyof WindowEventMap, callback: (event: Event) => void, element: HTMLElement | Document | (Window & typeof globalThis) = window) => void

Attaches a global event listener to the element (window object by default).

const EventListenerComponent = () => {
  const [value, setValue] = React.useState('Loading');

  useEventListener('load', () => {
    setTimeout(() => {
      setValue('Hello World!');
    }, 100);
  });

  return <div data-testid="test-value">{value}</div>;
};

useScript

type: (url: string) => AsyncObjectWithoutData

Loads in a script and adds a new script node to the DOM.

const ScriptComponent = () => {
  const { loading, error } = useScript(
    'https://code.jquery.com/jquery-3.6.0.min.js'
  );

  if (loading) return <div>Loading</div>;
  if (error) return <div>Error</div>;

  return (
    <div>
      {Object.keys(window)
        .includes('$')
        .toString()}
    </div>
  );
};

Util hooks

useTimeout

type: (callback: () => void, ms: number) => TimeoutObject

Basically setTimeout as a hook.

const TimeoutComponent = () => {
  const [count, setCount] = React.useState(10);
  const { clear, reset } = useTimeout(() => setCount(0), 1000);

  return (
    <div>
      <div>{count}</div>
      <button onClick={clear}>Clear</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
};

useDebounce

type: (callback: () => void, ms: number, deps: React.DependencyList = []) => void

const DebounceComponent = () => {
  const [count, setCount] = React.useState(0);
  const [dependency, setDependency] = React.useState(10);
  useDebounce(() => setCount(dependency), 200, [dependency]);

  return (
    <div>
      <div>{count}</div>
      <button onClick={() => setDependency(dependency + 1)}>Click Me!</button>
    </div>
  );
};

useTextShortener

type: (text: string, options: TextShortenerOptions) => string

Shortens a text to a specified limit. Customizable through options.

const TextShortenerComponent = (props: Omit<TextShortenerOptions, 'limit'>) => {
  const [limit, setLimit] = React.useState(11);
  const short = useTextShortener('Lorem ipsum dolor sit amet', {
    limit,
    ...props,
  });

  return (
    <div>
      <div>{short}</div>
      <button onClick={() => setLimit(6)}>Click Me!</button>
    </div>
  );
};

useOnlineStatus

type: () => boolean

Returns true or false. Depends on the browser agent status.

useRenderCount

type: () => number

useDebugInfo

type: <Props extends Record<string, any>>(Component: React.ComponentType<Props>, props: Record<string, any>) => DebugInfo

const DebugComponent: React.FC<{ count: number }> = props => {
  const [count, setCount] = React.useState(props.count);
  const debug = useDebugInfo(DebugComponent, { count });

  return (
    <div>
      <div>{JSON.stringify(debug)}</div>
      <button onClick={() => setCount(count + 1)}>Click Me!</button>
    </div>
  );
};

useLocalStorage

type: (key: string, defaultValue: Value) => StorageObject

Handles and stores data in window.localStorage

const LocalStorageComponent = () => {
  const { value, update, remove } = useLocalStorage('test', 'Hello World!');
  return (
    <div>
      <div>{value}</div>
      <button onClick={() => update('Hi')}>Update</button>
      <button onClick={() => remove()}>Remove</button>
    </div>
  );
};

useSessionStorage

type: (key: string, defaultValue: Value) => StorageObject

Handles and stores data in window.sessionStorage

const SessionStorageComponent = () => {
  const { value, update, remove } = useSessionStorage('test', 'Hello World!');
  return (
    <div>
      <div>{value}</div>
      <button onClick={() => update('Hi')}>Update</button>
      <button onClick={() => remove()}>Remove</button>
    </div>
  );
};

Asynchronous hooks

useAsync

type: <T = any>(promise: () => Promise<T>, deps: React.DependencyList = []) => AsyncObject<T>

Handles async functions, re-evaluates whenever a dependency changes

const AsyncComponent = (props: { success?: boolean }) => {
  const { loading, error, data } = useAsync<string>(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        props.success ? resolve('Hello World!') : reject({ message: 'Error' });
      }, 1000);
    });
  });

  return (
    <div>
      <div>{loading.toString()}</div>
      {error && <div>{JSON.stringify(error)}</div>}
      {data && <div>{data}</div>}
    </div>
  );
};

useFetch

type: <T = any>(config: FetchConfig, deps: React.DependencyList = []) => AsyncObject<T>

Handles API requests, uses the built-in fetch module

Types

AsyncObject

{
  loading: boolean;
  error: AsyncError | undefined;
  data: T | undefined;
}

AsyncError

{
  message: string;
  [key: number | string]: any;
}

DebugInfo

{
  renderCount: number;
  changedProps: Record<string, any>;
  timeSinceLastRender: number;
  lastRenderTimestamp: number;
}

FetchConfig

{
  url: string;
  options?: RequestInit
};

State

{
  [key: number | string]: any
};

StorageObject

{
  value: Value;
  update: (value: Value) => void;
  remove: () => void;
}

TimeoutObject

{
  reset: () => void;
  clear: () => void;
}

ToggleObject

{
  value: boolean;
  toggle: () => void
}

Value

string | number | boolean | Record<string, any> | null | undefined