Coder Social home page Coder Social logo

react-use's Introduction


npm package CircleCI master npm downloads demos
Collection of essential React Hooks. Port of libreact.
Translations: 🇨🇳 汉语

npm i react-use

Usage — how to import.
Unlicense — public domain.
Support — add yourself to backer list below.


react-use's People


renovate-bot avatar streamich avatar semantic-release-bot avatar xobotyi avatar wardoost avatar Belco90 avatar dependabot[bot] avatar ayush987goyal avatar ankithkonda avatar NullVoxPopuli avatar renovate[bot] avatar cleverjam avatar Granipouss avatar brickspert avatar kachkaev avatar jakapatb avatar ythecombinator avatar MrHuangJser avatar artywhite avatar zaguiini avatar liuyuchenzh avatar ddaza avatar PetterIve avatar gelove avatar KusStar avatar lvl99 avatar realdennis avatar Dosant avatar adesurirey avatar ClementParis016 avatar


evatrium avatar alanaudi avatar Manish Singh avatar Sergey avatar  avatar MingHui avatar Chaehyeon Lee avatar  avatar Jaewoo Gwak avatar  avatar Subin Yang avatar Martin Sztrikinácz avatar Yuri Karnilaev avatar cherish avatar  avatar Vladyslav Nyzhashchyy avatar Aleksandr Morozov avatar Robin Haider avatar Leonardo Juriolli avatar Jacques Germishuys avatar Dennis Prochniak avatar kenty avatar Ryan  Legler avatar Afif Arman avatar  avatar miamiamia avatar Jaeuk Lim avatar Julio Montas avatar Eren Demir avatar Çağdaş Tunca avatar David Ketchel avatar liuxsen avatar Iván Cárdenas Meneses avatar Alamin Hossain avatar Areum Yang avatar Guilherme Rigotti avatar Alesia Korzun avatar Thomas Arildtoft avatar Brezhnev Ivan avatar  avatar Juliana Barros Lima avatar dcernogorsky-equinix avatar mohamed boujaha avatar Konstantin Baklaev avatar Rodion Ramazanov avatar Alex Baretsky avatar Daan Heskes avatar Raphael Joer avatar Cores avatar Seunghun Sunmoon Lee avatar Samir Rustamov avatar  avatar Pete Willard avatar GArTech avatar  avatar  avatar  avatar KONY avatar kyle avatar  avatar kasu avatar Sergey Zhestovsky avatar Emilio Schaedler Heinzmann avatar K8sCat avatar  avatar Aquib Baig avatar Mert Güvençli avatar moli avatar Dmitry Kondratev avatar  avatar Abhi Dadhaniya avatar Mateus Gonçalves Franco avatar goduer avatar  avatar dagowaksdev avatar  avatar tuntun avatar yangxingyuan avatar Fan avatar  avatar Carlos Quiroz avatar qianxiu avatar Yasir Obaidullah avatar  avatar thisKim avatar irfan köprücü avatar Sohel Mia avatar chrllstian avatar rechard liu avatar Fernando Juriolli avatar Kevin Neaton avatar Evandro Rodrigues Coelho avatar Eryanto Agusriadi avatar Ray avatar Thomas Gleizes avatar Alex avatar  avatar Bill Molloy avatar Greg Wu avatar Free_zan avatar


Brandon Smith avatar Jani Krunniniva avatar Aarron Painter avatar Eugene avatar Adrian Lawrence avatar Uncle JorJ avatar Marcin Kumorek avatar  avatar Alan Garcia avatar Yuan Liang avatar zbchen avatar Gavin Daly avatar Adelar da Silva Queiróz avatar Lance He avatar kimhou avatar James Cloos avatar Kondal Rao Komaragiri avatar purwandi avatar Alan Zambrano avatar  avatar akbarwibawa avatar avatar zhangaz1 avatar Peixin Liu avatar Tam Nguyen avatar Michael Demarais avatar Jonathan avatar Justin Hachemeister avatar raoul avatar kirsantov avatar Luís Costa avatar Hannes Güdelhöfer avatar Murilo Henrique avatar Teboho Tsotetsi avatar Vladimir Mechkauskas avatar Ankith Konda avatar Florin Cosmin avatar Diogo Rafael Jacobs avatar LeeHyungGeun avatar derese.getachew avatar Jason Decastro avatar Vivam avatar Adriano Buscema avatar zhanglun avatar  avatar RCKT avatar Andrii Pavliuk avatar  avatar  avatar phantomk avatar Ihor Bondar avatar Go7hic avatar Eliran Zach avatar 小撸 avatar Ardamis Yeshak avatar  avatar Alexey Pyltsyn avatar rudy avatar Joe Zhong avatar Knock avatar Bin Chao avatar Shawn avatar Marcelo Dias avatar  avatar Mario Peric avatar  avatar  avatar Nícolas Deçordi avatar Huy Nguyen avatar  avatar Hung avatar Layer avatar  avatar Raman avatar Aldren Terante avatar  avatar Dmitriy avatar Florin Buga avatar  avatar ning chen avatar Jianyun Tang avatar shonibare omofolarin avatar Michealmiker avatar Choquet Nicolas avatar Binler avatar  avatar AlbertAz avatar PlayerWho avatar Ricardo Ruiz avatar RobR avatar 郭坚 avatar miniwa avatar Kelvin Tsoi avatar Vadim Dalecky avatar  avatar Brian Okanga avatar weaponhe avatar  avatar  avatar Liu Jia avatar

react-use's Issues

useLocation will break on IE11 without Event polyfill

This issue is just to note that useLocation will break on IE11 without a polyfill for window.Event. even when <meta http-equiv="x-ua-compatible" content="IE=edge"> is already in head.

IE9, 10 and 11 will break right here when new Event('pushstate'); is run by calling history.push('/something') in your react app.

const event = new Event(method.toLowerCase());

Object doesn't support this action

You need to polyfill window.Event which import '@babel/polyfill'; is not doing for you. So here goes what I've added to my polyfill.js

 * To detect you are in IE (for this case) by checking typeof(Event) which is
 * 'function' for all except IE where it is 'object'.
 * You can then safely polyfill the Event constructor using the approach above.
 * In IE11 it seems to be safe to set window.Event = CustomEvent.
(function() {
    if (typeof window.Event === 'function') return false; //If not IE

    function CustomEvent(event, params) {
        params = params || {
            bubbles: false,
            cancelable: false,
            detail: undefined,
        var evt = document.createEvent('CustomEvent');
        return evt;

    CustomEvent.prototype = window.Event.prototype;

    window.Event = CustomEvent;

The solution was provided here (accepted answer). Don't skip the comments.

usePagination / usePaginator

What about that possible hook?

type HookProps =  [number, (position: number): number, ?number];

type HookParams = {
    pageSize: number, 
    collectionSize: number,
    initialCurrentPage: ?number = 1,

function ListComponent() {
    const params: HookParams = { 

    const [currentPage, gotoPage, totalPages]: HookProps = usePaginator(params);
    const gotoNext = (): number => gotoPage(currentPage + 1)
    const gotoPrev = (): number => gotoPage(currentPage - 1)

    return (
        <Pagination {...} />


Add useLocalStorage hook.

const [value, setValue] = useLocalStorage('key', initialValue);


It would be nice to have useThrottle, implemented similarly to useDebounce

state should be reset before the second call in useAsync

since after the first call,state.loading was set to false in useEffect.After then state.loading would still be false in the second call for refetching.
so maybe state should be reset in useEffect:

    () => {
      let mounted = true;
      set({ loading: true }); // reset state
      const promise = memoized();
        value => {
          if (mounted) {
              loading: false,
        error => {
          if (mounted) {
              loading: false,
      return () => {
        mounted = false;


Explicitly defining the licence will ensure there are no future developer concerns about whether or not this module is for them. May I suggest a permissive license such as MIT or Apache?

improve/extend async state for useAsync and related hooks

just like Query Mutation in react-apollo:

<Query query={gql_document} variables={variables}>
  {({ data, error, loading }) => <div></div>}

<Mutation mutation={gql_document}>
  {(mutation_api, mutation_result) => {
    const { data, error, loading } = mutation_result;
    return <div></div>

And now we have useAsync, but it can only act as Query.

We should have an useApi to act as Mutation.

// A very very naive implementation
const useApi = (promisified_api, variables) => {
   const [state, set_state] = useState({loading: !!variables});
   const api = async (...variables) => {
    const data = await promisified_api(...variables);
  // we should expose `set_state`, it can act as Query's updteQuery, and use can set_state({error:null}) manually when close the error dialog.
  return [api, state, set_state];

const [api, state, set_state] = useApi(fn_return_promise, maybe_variables);

Adding sessionStorage - API options

Would like to add useSessionStorage.

Options API-wise:

  1. Just copy-paste useLocalStorage and s/local/session
  2. In useLocalStorage.ts, add a parameter called storageKey that defaults to 'localStorage' and have useSessionStorage just call that. Then in useLocalStorage, s/localStorage/window[storageKey]

What would you prefer?


Add React Hooks that can be used component lifecycles.


  • Start adding unit tests for hooks.
  • What are the best practices for testing React Hooks?

Pending tests to be added

  • State block
    • createMemo
    • createReducer
    • useBoolean
    • useCounter
    • useNumber
    • useGetSet
    • useGetSetState
    • useList
    • useMap
    • useObservable
    • usePrevious
    • useSetState
    • useToggle
    • useDefault
  • Animation block
    • useRaf
    • useSpring
    • useTimeout
    • useTween
    • useUpdate
    • useTimeoutFn
    • useInterval
  • Lifecycle block
    • useDeepCompareEffect
    • useEffectOnce
    • useIsomorphicLayoutEffect
    • useLifecycles
    • useLogger
    • useMount
    • useMountedState
    • usePromise
    • useRefMounted
    • useUnmount
    • useUpdateEffect


Hook that creates a dispatcher for errors, that can be caught with error boundaries.

const useError = () => {
  const [err, raise] = useState();

  if (err) {
    throw err;

  return raise;

const Demo = () => {
  const raise = useError();

  useEffect(() => {
    setTimeout(() => {
        new Error("Could not work with setTimeout for some reason!")
    }, 1000);

  return <div>Hello world</div>;

Alternative names: useError, useRaise, useThrow, useErrorDispatch.

Seen here: reactjs/rfcs#84 🧐

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.

Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry

If you are using Two-Factor Authentication, make configure the auth-only level is supported. semantic-release cannot publish with the default auth-and-writes level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.

Good luck with your project

Your semantic-release bot 📦🚀


Convert DropArea to useDropArea hook.

const [el] = useDropArea(<div/>, {
  onFiles: () => {},
  // ...


const ref = useRef();
useDropArea(ref, {
  onFiles: () => {},
  // ...

cancelAnimationFrame may not work well in useRaf hook

I think the logic here may not let current animation stop perfectly, which may lead to memory leak or related things.

As cancelAnimationFrame method is executed in the clean-up period, the animation ID "stored" in raf can be perfectly cancelled. However, the onFrame method may continues (especially when the main thread render DOM slowly, and it will take sometime between useEffect doing cleaning work and your requestAnimationFrame method's running, ), so that a new raf will be assigned, even though you already canvel previous raf.

In this way, you don't clean up previous animation, and next effect will bring in a new animation, which is the problem.

In my opinion, a safe way to guarantee current animation's stop is to add conditions in your main loop method, onFrame method can be rewrited to:

const onFrame = () => {
      const time = Math.min(1, ( - start) / ms);
	  } else {

const stop = () => {

in which YOUR_CANCEL_CONDITION is the logic you should handle with.

EditorConfig require

@streamich I think it's good idea to put EditorConfig in this project to make sure all contributors have the same configuration and prevent unnecessary the code formatting change over each PR.



Any idea on useForm with (async) validation as a hook ?

Configure ESM build

It would be great to support ESModules to provide better tree shaking, rollup might be helpful

P.S. I mean mjs format

Full IE11 support

First of all, thank you for this package, it has been very useful for my projects!
I've noticed the production build it's not fully compatible with IE11.
I managed to do a "manual tree-shake" using babel-plugin-transform-imports, but i still get errors on IE11 using some hooks, e.g:

// ...
// production build of useWindowSize, IE11 won't be able to destructure this
const [state, setState] = react_1.useState({
  width: isClient ? window.innerWidth : initialWidth,
  height: isClient ? window.innerHeight : initialHeight,
// ...

My question is: can we add a .browserslistrc on the package, so we can get full support for older browsers in the production build?


Here's a plain Javascript version that I'm using in my application:

function useUserMedia(constraints, errorCallback=(()=>undefined)) {
    const [stream, setStream] = useState();

    useEffect(_ => {
    }, [stream]);

    return stream;

To get user's front camera and audio feed:

const constraints = {
    video: true,
    audio: true

const onError = (e) => alert(e);

const localstream = useUserMedia(constraints, onError);

useTranslate() for component localization ?

An idea for lazy component localization with code splitting.

Suppose we want to localize component named UserProfile

// UserProfile.jsx
const UserProfile = ({ firstName, lastName }) => {
   return (
      Hello, {firstName}!
      <div>First Name: {firstName}</div>
      <div>Last Name: {lastName}</div>
        Full Name: {firstName} {lastName}

At first we should define dynamically imported translations file per language:

// UserProfile.rus.jsx
export default {
  "First Name": "Имя",
  "Last Name": "Фамилия",
  "Hello, ${name}!": name => `Привет, ${name}!`,
  footer: (firstName, lastName) => (
      Полное Имя: {firstName} {lastName}

Translation file is plain object, which values are strings or functions returning strings or even JSX markup.

Then we create React Context for locale LocaleContext = React.createContext() and new hook named useTranslate. It loads translations file on every context change and returns translation function to a component.

// UserProfile.jsx
const UserProfile = ({ firstName, lastName }) => {
  // translation function
  const tr = useTranslate(lang =>
    import(/* webpackChunkName: "i18n-" */ `./UserProfile.${lang}.jsx`)

  return (
      {tr`Hello, ${firstName}!`}
        {tr`First Name`}: {firstName}
        {tr`Last Name`}: {lastName}
      {tr("footer", firstName, lastName) || (
          Full Name: {firstName} {lastName}

Translation function can work in two modes:

  • As ES6 template tag it extracts key and arguments from passed template, and also returns raw ES6 template value as fallback if key is not found in translations object.
  • As regular function it uses first argument for key lookup and passes rest arguments to translation template.


  • We can localize each component independently.
  • Or we can create common resources and utilities and import them in each component translations file.
  • Or we can group translations in other ways.

Implementation can be found here: gist (about 100 SLOC).
If this is interesting, I can submit a PR.

useDebounce should recompute on delay change

Currently useDebounce only creates a new timeout if args change. Is there any reason for this?

I tried adding delay to args like this:

useDebounce(() => setDebouncedState(state), delay, [state, delay]);

But this causes an additional (= unnecessary) rerender.

TL;DR Scroll down to EDIT 4

I'm trying to create a useDebouncedState hook, with dynamic debounce, like this:

const useDebouncedState = <T>(initialState: T): [T, T, (state: React.SetStateAction<T>, delay?: number) => void] => {
    const [delay, setDelay] = useState(0);
    const [state, setState] = useState(initialState);
    const [debouncedState, setDebouncedState] = useState(initialState);

    const updateDebouncedState = useCallback(() => {
        if(state !== debouncedState) {
    }, [state, debouncedState]);

    useDebounce(updateDebouncedState, delay, [state]);

    const updateState = useCallback((nextState: React.SetStateAction<T>, delay: number = 0) => {
        if(nextState instanceof Function) {
            nextState = nextState(state);

        if(delay <= 0) {
    }, [state]);

    return [state, debouncedState, updateState];

It works fine, as long as the state changes. But it won't trigger when I pass equal state with a new delay to updateState.

What it's intended to do:

  • store a whole object
  • some state changes should be debounced (for example search query input). So here I'd use setState({...state, query: ''}, 300).
  • other state changes should trigger immediately (for example click on the search button, or clicking a checkbox). And here: setState(state, 0) or setState({...state, checkbox: true}, 0).
  • state is the current state, which can be used as value for input fields
  • debouncedState can be used with useEffect to detect, when to trigger an action (for example execute API request)

Test code:

const [state, debouncedState, setState] = useDebouncedState("foo");

useEffect(() => {
    const s = "bar";

    setTimeout(() => {
        setState(s, 5000);
    }, 0);
    setTimeout(() => {
        setState(s, 0); // this won't do anything, because only delay changed
    }, 1000);
}, [])

EDIT: Maybe you could also add an optimization:

if(ms < 1) {
    fn.bind(null, args)();
} else {
    const t = setTimeout(fn.bind(null, args), ms);

This prevents rerender, when using zero (or negative) delay.

Btw: Is there any need for using bind instead of simply fn(args)?

EDIT 2: Here's what all my changes look like:

  const useDebounce = (fn: () => any, ms: number = 0, args: Array<any> = []) => {
    const [timeout, setTimeoutVar] = useState<any>(null);
    useEffect(() => {
      // if args change then clear timeout
      if(ms < 1) { // optimization for zero-delay
        fn.bind(null, args)();
      } else {
        const t = setTimeout(fn.bind(null, args), ms);
    }, [ms, ...args]); // here I added `ms`

EDIT 3: Another optimization would be to remove const [timeout, setTimeoutVar]. Because setTimeoutVar(t); will trigger a rerender, too.

My tests showed that this code for useDebounce rerenders less:

  const useDebounce = (fn: () => any, ms: number = 0, args: Array<any> = []) => {
    useEffect(() => {
      // if args change then clear timeout
      let t: any;
      if(ms < 1) {
        fn.bind(null, args)();
      } else {
        t = setTimeout(fn.bind(null, args), ms);

      return () => { // use this callback for clearTimeout, it has been
        clearTimeout(t); // suggested by Dan Abramov himself:
      } //
    }, [ms, ...args]);

Though I'm not sure if it's breaking change? But it seems to works fine.

EDIT 4: Forget (nearly) everything I said 😆

It looks like setTimeoutVar(t); is the only real problem that causes unnecessary rerenders!

So... This code seems to work fine in combination with useDebounce(() => ..., delay, [state, delay]):

  const useDebounce = (fn: () => any, ms: number = 0, args: Array<any> = []) => {
    useEffect(() => {
      let handle = setTimeout(fn.bind(null, args), ms);

      return () => {
        // if args change then clear timeout
    }, args);

Issue with SSR?

I tried to use the package on next.js and it throws the following error:

Error: Addon "cssom" is missing the following dependencies:
    at warnOnMissingDependencies (/Users/rafael/Code/blumpa-ssr/node_modules/nano-css/addon/__dev__/warnOnMissingDependencies.js:23:15)
    at exports.addon (/Users/rafael/Code/blumpa-ssr/node_modules/nano-css/addon/cssom.js:5:55)
    at Object.<anonymous> (/Users/rafael/Code/blumpa-ssr/node_modules/react-use/lib/useCss.js:27:1)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/rafael/Code/blumpa-ssr/node_modules/react-use/lib/index.js:17:18)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)


Use the same as useState but with shallow compare

Remove large dependencies

This library minified is almost 52kb, which is huge for what it is. 60% of the bundle size is solely based on dependencies, all of which are only used in a few hook.

I would suggest making turning those into peerDependencies and requiring users to include the libraries in their own package.json. This would make the size of this library ~21kB.

Although tree shaking should take care of this, not all environments support it, and forcing dependencies on users isn't the best course of action, especially if it's for a small functionality.

If this is a go, I could make the PR with the changes (code & docs) required for this.

TypeScript build fails

I’ve enabled the strict option in my tsconfig.json, and installing this package results in an error because it can’t find types for the useCallbag hook, even though I don’t use that hook. It seems to be trying to import the types for the use-callbag package, which don’t exist. Can you fix this error?


I'd like to have some useDistinct hook, which takes a value (or another hook) and only changes state if the returned value has changed.

It's kinda the opposite way of useMemo. It should rerender based on output instead of input value.

I'm not sure if that's possible at all...


const compareFn = (oldValue, newValue) => {
    return oldValue[0] === newValue[0];

const MyComponent = (props) => {
    const [state, setState] = useDistinct(useState("foo"), compareFn);
    console.log("rerendered", state)

    return (
      <button onClick={() => setState("foo")}>Change State</button>

When not using useDistinct, every call to setState will rerender the component. Even if you call setState(state).
When using useDistinct, it should check for === equality. Or you can provide a custom comparison function which does the equality check.


Hey there!

Saw that you already got use-styles on npm, but couldn't find anything on GitHub.

Are you actively working on something? Would be keen to share experiences, since I have been working on something very similar:


[Maybe bug] use-css component twinkles

Some of my pages and components use use-css to style, but when I switched to them, them would always twinkle at first, without styles and become normal in the next flash.

version: react-use 5.7.1

useDebounce types improvement

I would like to propose a better typed version of your useDebounce, here my actual step:

import { useEffect, useRef } from 'react';
import cloneDeep from 'lodash/fp/cloneDeep';
import noop from 'lodash/fp/noop';

// ------------------------------------------------------------ # Type aliases #

type AnyCallback = (...args: any[]) => any;
type Debounce<Callback extends AnyCallback> = (...params: Parameters<Callback>) => void;

// -------------------------------------------------------------------- # Hook #

export default function useDebounce() {
  return <Callback extends AnyCallback>(callback: Callback, delay = 250) => {
    const timer = useRef<NodeJS.Timeout>(null);
    const debounce = useRef<Debounce<Callback>>(noop);

    useEffect(() => {
      debounce.current = (...params: Parameters<Callback>) => {
        const paramsCopy = cloneDeep(params);

        if (timer.current) {

        // @ts-ignore
        timer.current = setTimeout(() => callback(...paramsCopy), delay);
    }, []);

    return debounce.current;


import useDebounce from './path/to/useDebounce'

function Component() {
  const debounce = useDebounce()

  function handleClick(event: React.ChangeEvent<HTMLInputElement>) {
    console.log('Clicked with debounce')

  return <input type="text" onChange={debounce(handleClick)} />

Any remark will be highly appreciated!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.