Home

Awesome

🙋‍♂️ Made by @thekitze

Other projects:

<a href="https://zerotoshipped.com"><img style="width:450px" src="https://i.ibb.co/WKQPDv5/twitter-image.jpg" alt="Zero To Shipped"></a>

react-hanger

npm version

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

All Contributors

<!-- ALL-CONTRIBUTORS-BADGE:END -->

Set of a helpful hooks, for different specific to some primitives types state changing helpers.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tr> <td align="center"><a href="http://liveflow.io"><img src="https://avatars.githubusercontent.com/u/3940079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrey Los</b></sub></a><br /><a href="#ideas-RIP21" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-RIP21" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/kitze/react-hanger/commits?author=RIP21" title="Tests">⚠️</a> <a href="https://github.com/kitze/react-hanger/commits?author=RIP21" title="Code">💻</a></td> <td align="center"><a href="https://praneet.dev"><img src="https://avatars.githubusercontent.com/u/23721710?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Praneet Rohida</b></sub></a><br /><a href="#infra-praneetrohida" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/kitze/react-hanger/commits?author=praneetrohida" title="Tests">⚠️</a> <a href="https://github.com/kitze/react-hanger/commits?author=praneetrohida" title="Code">💻</a></td> </tr> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the all-contributors specification. Contributions of any kind welcome!


Has two APIs:

Install

yarn add react-hanger

Usage

import React, { Component } from 'react';

import { useInput, useBoolean, useNumber, useArray, useOnMount, useOnUnmount } from 'react-hanger';

const App = () => {
  const newTodo = useInput('');
  const showCounter = useBoolean(true);
  const limitedNumber = useNumber(3, { lowerLimit: 0, upperLimit: 5 });
  const counter = useNumber(0);
  const todos = useArray(['hi there', 'sup', 'world']);

  const rotatingNumber = useNumber(0, {
    lowerLimit: 0,
    upperLimit: 4,
    loop: true,
  });

  return (
    <div>
      <button onClick={showCounter.toggle}> toggle counter </button>
      <button onClick={() => counter.increase()}> increase </button>
      {showCounter.value && <span> {counter.value} </span>}
      <button onClick={() => counter.decrease()}> decrease </button>
      <button onClick={todos.clear}> clear todos </button>
      <input type="text" value={newTodo.value} onChange={newTodo.onChange} />
    </div>
  );
};

Example

Edit react-hanger example

API reference (object destructuring)

How to import?

import { useBoolean } from 'react-hanger' // will import all of functions
import useBoolean from 'react-hanger/useBoolean' // will import only this function

useStateful

Just an alternative syntax to useState, because it doesn't need array destructuring. It returns an object with value and a setValue method.

const username = useStateful('test');

username.setValue('tom');
console.log(username.value);

useBoolean

const showCounter = useBoolean(true);

Methods:

useNumber

const counter = useNumber(0);
const limitedNumber = useNumber(3, { upperLimit: 5, lowerLimit: 3 });
const rotatingNumber = useNumber(0, {
  upperLimit: 5,
  lowerLimit: 0,
  loop: true,
});

Methods:

Both increase and decrease take an optional amount argument which is 1 by default, and will override the step property if it's used in the options.

Options:

useInput

const newTodo = useInput('');
<input value={newTodo.value} onChange={newTodo.onChange} />
<input {...newTodo.eventBind} />
<Slider {...newTodo.valueBind} />

Methods:

Properties:

useArray

const todos = useArray([]);

Methods:

    So if input is [1, 2, 3, 4, 5]

    from  | to    | expected
    3     | 0     | [4, 1, 2, 3, 5]
    -1    | 0     | [5, 1, 2, 3, 4]
    1     | -2    | [1, 3, 4, 2, 5]
    -3    | -4    | [1, 3, 2, 4, 5]

useMap

const { value, set } = useMap([['key', 'value']]);
const { value: anotherValue, remove } = useMap(new Map([['key', 'value']]));

Actions:

useSet

const set = useSet(new Set<number>([1, 2]));

useSetState

const { state, setState, resetState } = useSetState({ loading: false });
setState({ loading: true, data: [1, 2, 3] });
resetState();

Methods:

Properties:

usePrevious

Use it to get the previous value of a prop or a state value. It's from the official React Docs. It might come out of the box in the future.

const Counter = () => {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  return (
    <h1>
      Now: {count}, before: {prevCount}
    </h1>
  );
};

usePageLoad

const isPageLoaded = usePageLoad();

useScript

const { ready, error } = useScript({
  src: 'https://example.com/script.js',
  startLoading: true,
  delay: 100,
  onReady: () => {
    console.log('Ready');
  },
  onError: (error) => {
    console.log('Error loading script ', error);
  },
});

useDocumentReady

const isDocumentReady = useDocumentReady();

useGoogleAnalytics

useGoogleAnalytics({
  id: googleAnalyticsId,
  startLoading: true,
  delay: 500,
});

useWindowSize

const { width, height } = useWindowSize();

useDelay

const done = useDelay(1000);

usePersist

const tokenValue = usePersist('auth-token', 'value');

useToggleBodyClass

useToggleBodyClass(true, 'dark-mode');

useOnClick

useOnClick((event) => {
  console.log('Click event fired: ', event);
});

useOnClickOutside

// Pass ref to the element
const containerRef = useOnClickOutside(() => {
  console.log('Clicked outside container');
});

useFocus

// pass ref to the element
// call focusElement to focus the element
const [elementRef, focusElement] = useFocus();

useImage

const { imageVisible, bindToImage } = useImage(src, onLoad, onError);

Migration from v1 to v2

useOnMount(() => console.log("I'm mounted!"));
useOnUnmount(() => console.log("I'm unmounted"));
// OR
useLifecycleHooks({
  onMount: () => console.log("I'm mounted!"),
  onUnmount: () => console.log("I'm unmounted!"),
});

to:

useEffect(() => {
  console.log("I'm mounted!");
  return () => console.log("I'm unmounted");
}, []);