Coder Social home page Coder Social logo

uidotdev / usehooks Goto Github PK

View Code? Open in Web Editor NEW
8.5K 60.0 471.0 3.03 MB

A collection of modern, server-safe React hooks – from the ui.dev team

Home Page: https://usehooks.com

License: MIT License

JavaScript 17.05% CSS 3.66% Astro 9.95% TypeScript 4.70% MDX 64.64%
react hooks blog astro react-hooks vercel

usehooks's Introduction

usehooks's People

Contributors

alexanderson1993 avatar arditgjeloshaj avatar benadam11 avatar bozheville avatar csenio avatar danedavid avatar dependabot[bot] avatar emzoumpo avatar faizaniqballc avatar fredrikekelund avatar gragland avatar hermannygaard avatar jack0pan avatar jeniabrook avatar justin-gurtz avatar lewandy avatar lguardado avatar lynnandtonic avatar nikasepiskveradze avatar nmenglund avatar nsdonato avatar paulrberg avatar philipp985 avatar prjanja avatar thebuilder avatar trueloving avatar twhitbeck avatar tylermcginnis avatar vandycknick avatar vanillajonathan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

usehooks's Issues

How to hook window.onload?

window.addEventListener('load', handleResize)

    return () => {
      window.removeEventListener('load', handleResize)
    };

the code above do not run in useLayoutEffect or useEffect

How to hook window.onload?

useAutoScroll

Here is a custom hook I extracted recently from a project. It basically allows the user to use a selector query to grab a number of DOM nodes, and then move through them one by one by clicking buttons.

Central code looks like this:

const useAutoScroll = (node, selector) => {
  const [position, setPosition] = useState(0);
  const [target, setTarget] = useState(null);
  const steps = useRef([
    {
      scrollIntoView: () => {
        window.scrollTo({ top: 0, behavior: "smooth" });
      }
    }
  ]);

  // grabs the DOM nodes that are targeted by the selector, and saves them to the steps ref
  useEffect(
    function grabJumpPoints() {
      if (node) {
        const cards = node.querySelectorAll(selector);
        steps.current.splice(1, steps.current.length - 1);
        cards.forEach(card => {
          steps.current.push(card);
        });
      }
    },
    [node]
  );

  // tracks updates to target, and scrolls the screen to them when target updates
  useEffect(
    function scrollToTarget() {
      if (steps.current && typeof target === "number") {
        const current = steps.current[target];
        current.scrollIntoView({ behavior: "smooth", block: "start" });
      }
    },
    [target]
  );

  // updates the current position as the user scrolls (or from programatic scrolling)
  const updateScroll = () => {
    if (node && position !== undefined) {
      const scrollDistance = window.scrollY || 0;
      let newPoint = 0;

      steps.current.forEach((point, index) => {
        // subtract 10 to give some leeway if autoscroll stops a few pixels short
        if (scrollDistance > point.offsetTop - 10) {
          newPoint = index;
        }
      });
      setPosition(newPoint);
    }
  };

  // initialize scroll behavior with event listener
  useEffect(
    () => {
      document.addEventListener("scroll", updateScroll);

      // return cleanup behavior
      return () => window.removeEventListener("scroll", updateScroll);
    },
    [node, steps]
  );

  // function exposed to consuming component
  const scrollNext = () => {
    const nextPoint = (position + 1) % steps.current.length;
    setTarget(nextPoint);
  };

  // function exposed to consuming component
  const scrollBack = () => {
    const candidate = position - 1;
    const prevPoint =
      candidate >= 0 ? candidate : steps.current.length + candidate;
    setTarget(prevPoint);
  };
  return { scrollNext, scrollBack, position };
};

Codebox is attached here showing the basic idea.

Does this make sense as something to include in a PR? Would love any feedback!

usePropState (TypeScript)

How do you feel about adding typescript to useHooks?

For instance I am working on this setState wrapper which allows a typesafe way to set a property of the state:

import { Dispatch, SetStateAction, useState } from 'react';

/**
 * This hook is a supplement to setState - https://reactjs.org/docs/hooks-state.html
 * It let's you update a property of the state in a typesafe way.
 *
 * @param initialState - the initial state for this hook, it is forwared to useState
 *
 * @returns
 * [state, setPropState, setState]
 * state is the state returned from the useState hook.
 * setPropState is the typesafe function for updating a part of the state.
 * setState is the normal setState function for setting the entire state at once.
 */
export const usePropState = <T>(
  initialState: T
): [T, <K extends keyof T>(part: K) => (value: T[K]) => void, Dispatch<SetStateAction<T>>] => {
  const [state, setState] = useState(initialState);

  const setPropState = <K extends keyof T>(part: K) => (value: T[K]) => {
    setState({ ...state, [part]: value });
  };

  return [state, setPropState, setState];
};

useScript adds script to cache before it was loaded

Had this issue when I used it.

useScript adds the scripts to the cache before it was loaded.
That means that if you in edge cases where you use the useScript twice in the same file. for example one of the scripts will return true before the script was actually loaded.

the fix is just to add to cache once the script loaded.

here is my version of the hook:

import { useEffect, useState } from 'react';

const cachedScripts = new Set();
function useScript(src) {
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState(false);
  useEffect(() => {
    if (cachedScripts.has(src)) {
      setLoaded(true);
      setError(false);
    } else {
      const script = document.createElement('script');
      script.src = src;
      script.async = true;

      const onScriptLoad = () => {
        cachedScripts.add(src);
        setLoaded(true);
        setError(false);
      };

      const onScriptError = () => {
        if (cachedScripts.has(src)) {
          script.delete();
        }
        setLoaded(true);
        setError(true);
      };

      script.addEventListener('load', onScriptLoad);
      script.addEventListener('error', onScriptError);

      document.body.appendChild(script);

      return () => {
        script.removeEventListener('load', onScriptLoad);
        script.removeEventListener('error', onScriptError);
      };
    }
  }, [src]);

  return [loaded, error];
}

export default useScript;

Add a search functionality to search for the particular hook

First I'd like to thank you for this website. It's really handy to check available hooks that I can use in my projects.

The list of hooks has grown since this project started. At this time a suggestion from me is to have a search input to search for a particular hook. Now I have to go through all pages to check for a hook that I want to use.

useMediaMatches

A hook which is simlar to the useMedia hook, but uses listeners on the media query so that it can listen to any type of media change and not only screen size.

import json2mq from 'json2mq';
import { useEffect, useState } from 'react';

function useMediaMatches(query, defaultMatches = false) {
  const [matches, setMatches] = useState(defaultMatches);
  const queryString = typeof query !== 'string' ? json2mq(query) : query;
  useEffect(
    () => {
      const update = event => setMatches(event.matches);
      const mediaQueryList = window.matchMedia(queryString);
      setMatches(mediaQueryList.matches);
      mediaQueryList.addListener(update);
      return () => mediaQueryList.removeListener(update);
    },
    [queryString]
  );
  return matches;
}

json2mq is useful if you want to write your media queries as objects, but is otherwise optional.

import { useEffect, useState } from 'react';

function useMediaMatches(query, defaultMatches = false) {
  const [matches, setMatches] = useState(defaultMatches);
  useEffect(
    () => {
      const update = event => setMatches(event.matches);
      const mediaQueryList = window.matchMedia(query);
      setMatches(mediaQueryList.matches);
      mediaQueryList.addListener(update);
      return () => mediaQueryList.removeListener(update);
    },
    [query]
  );
  return matches;
}

Minor typo: const App(){

Minor typo in first codeblock (the useLockBodyScroll example):

const App(){

const should be function:

function App(){

(it's right in CodeSandBox.) (Or of course, const App = () => {, but it's function in CodeSandBox, so best to be consistent.)

Add next/prev links at bottom of post permalink

Would be better then just linking back to homepage, particularly when coming from the first post on the homepage since you then need to scroll down to find more content. Ideally would have name of next/prev post and truncated description.

Some hook ideas

Hey there, I really like your blog idea so I'd like to share some of my hooks with you. They might not be perfect but feel free to refine the ideas and share them with the world:

  • useLocked
    This hook "locks" a callback when it is called, not allowing it to be called until the first call has ended.

  • useTask
    This hook wraps a callback and anytime this callback is called it will set a "isWorking" state and then set this state back to false once the callback has completed its work. It returns and object exposing the "task callback" and its "working" state. Allows you to easily show spinners or modify components based on an event callback (for example form submission).

  • useModel
    This hook is not really refined and it was mostly tuned for my personal needs but its idea is to provide an easy way to model inputs to an object. For example it may be used to model the values of a form into an object which may then easily be sumibtted.

Feel free to check out the other handful of hooks in the repo, but they are mostly fit for my projects' needs and probably won't be of use to the general public or you've already posted them or something really similar.

Publish to npm?

These hooks look cool, but did you consider publishing them to npm as libraries? So it will be possible to update dependencies, instead of having a constant copy inside our own repo?

P.S. The only important note here I'd like to mention, - to make possible to use these type of imports:

import useAuth from 'usehooks/useAuth'

Rather than:

import { useAuth } from 'usehooks'

Afaik, tools like NextJS optimize their buindles based on from values (well, it's not just NextJS, it's specific configuration for Webpack). I.e. by describing:

from 'usehooks/useAuth'

It will bundle only this useAuth part and its dependencies, rather than whole usehooks library.

P.P.S. npmjs.com/usehooks is free for now btw

useAsync and useFetch

Just released React Async v4 🚀 https://github.com/ghengeveld/react-async

useFetch is new in v4:

import { useFetch } from "react-async"

const MyComponent = () => {
  const headers = { Accept: "application/json" }
  const { data, error, isLoading } = useFetch("/api/example", { headers })
  // This will setup a promiseFn with a fetch request and JSON deserialization.
}

useAsync takes any promise and offers more flexibility:

import { useAsync } from "react-async"

const loadCustomer = ({ customerId }, { signal }) =>
  fetch(`/api/customers/${customerId}`, { signal })
    .then(res => (res.ok ? res : Promise.reject(res)))
    .then(res => res.json())

const MyComponent = () => {
  const { data, error, isLoading } = useAsync({ promiseFn: loadCustomer, customerId: 1 })
  if (isLoading) return "Loading..."
  if (error) return `Something went wrong: ${error.message}`
  if (data)
    return (
      <div>
        <strong>Loaded some data:</strong>
        <pre>{JSON.stringify(data, null, 2)}</pre>
      </div>
    )
  return null
}

Also supports AbortController for fetch cancellation.

useVariable hook idea

As addition to the existing useRef hook I think it's useful to have a useVariable hook which mimics the semantics of useState but do not trigger a component rerender.
It can be used in any situations where useRef would be used. Like saving the changes in a variable when onChange was called on an outer component.

The useVariable hook could look like:

import { useCallback, useRef } from 'react';

const useVariable = initialValue => {
    const ref = useRef(initialValue);
    const setter = useCallback(
        param => {
            ref.current = typeof param === 'function' ? param(ref.current) : param;
        },
        [ref]
    );
    return [ref.current, setter];
};

const [variable, setVariable] = useVariable('foobar')

I would love to hear your feedback on that one

useEffect inside useWindowSize should not return false

As the title says, in useWindowSize, inside useEffect there is a code:

useEffect(() => {
    if (!isClient) {
      return false;
    }
   // ...
  }, []);

If you use typescript, you'll see error:

  Type 'false | (() => void)' is not assignable to type 'void | (() => void | undefined)'.
    Type 'false' is not assignable to type 'void | (() => void | undefined)'

That's why useEffect should just return nothing, like this:

useEffect(() => {
    if (!isClient) {
      return;
    }
   // ...
  }, []);

useDocumentTitle

React hook for updating the document-title

import useDocumentTitle from '@rehooks/document-title';
 
function MyComponent() {
  useDocumentTitle('Page Title');
  return <div/>;
}

Repo conversion to TypeScript

Hey man, looks like you have your hands full with all these issues. Just wanted to reach out a hand of support for any pending issues as well as convey a willingness to convert the repo TypeScript. Since we last worked together I've got a little bit more Gatsby experience under my belt so I feel as though a TS conversion would be a fairly straightforward endeavor. Let me know what you think.

useToggle

This hook is implemented many times by many other developer, but i think for it's simplicity and learning purpose to other developers, we should upload this hook on site.

Basically, what this hook does is that, it takes an parameter with value true or false and toggles that value to opposite.
It's useful when we want to take some action into it's opposite action, for example: show and hide modal, show more/show less text, open/close side menu.

As you see, it has one parameter which only takes boolean value and default argument "false".

In this line we switch current value to it's opposite, useCallback hook returns the memorizes function reference and it's second argument "[]" empty array makes sure that returned function only defined once so it won't cause unnecessary rendering, also when we set the value in setState function we pass callback function to it, because every next value is computed from previous value, which guarantees fact that value will change to it's opposite value

const toggle = useCallback(() => setState(state => !state), []);

import { useCallback, useState } from 'react';

function useToggle(initialState = false) {
  const [state, setState] = useState(initialState);
  const toggle = useCallback(() => setState(state => !state), []);

  return [state, toggle];
}

export default useToggle;

Appreciation

I was faced with onClickoutside issue in my component.

I was using react-onclickoutside package prior to now.

I notice two strange issues.

First, when I have two instances of the same component in the same page, onclickoutside does not work properly.
Secondly, it does not work on when the component was nested in another component.

I researched and found the useOnClickOutside hook.
After applying the hook, alll the issues above disappeared.

Thanks

useTimeout

This hook could be used for setting a className on a component for a short time or simply delaying some action on mount.

import { useEffect, useState } from 'react';

/**
 * React Hook to abstract a timeout, if the onTimeout param is falsy the timer
 * will not be set, otherwise the timer will be set and that function will be
 * called at the end of the supplied duration.
 *
 * @param {Function|boolean?} onTimeout - a function to call on time out
 *  - if this value is falsy the timeout will NOT start.
 *  - if this param changes while a timeout is set, the timeout will be cleared
 * @param {{deps: ?Array, duration: number}} options
 *  - deps - passed in to useEffect deps
 *  - duration - in milliseconds, the duration of timeout
 *
 * @returns {boolean} - true if the timeout has been set and has not completed
 */
const useTimeout = (onTimeout = null, { deps, duration } = {}) => {
  const [isActive, setIsActive] = useState(false);

  useEffect(() => {
    let timer;
    if (onTimeout) {
      clearTimeout(timer);
      timer = setTimeout(() => {
        typeof onTimeout === "function" && onTimeout(); // only call if it is a function
        setIsActive(false);
      }, duration);
      setIsActive(true);
    }

    return () => {
      clearTimeout(timer);
    };
  }, deps);

  return [isActive];
};

export default useTimeout;

Examples

A. as an animation className timer on mount

const MyComponent = (props) => {
  const [isActive] = useTimeout(true, { deps: [], duration: 3000 });
  return (<div className={isActive && "green"}>Content Is Green on mount for 3seconds</div>);
}

B. as a trigger for showing content temporarily when it has changed

const ToastMessage = ({ message }) => {
  const [isActive] = useTimeout(message, { deps: [ message ], duration: 5000 });
  return (
    <div className="message-container">
      Once a changed message is received it will show for 5 seconds
      {isActive && message && <span className="message">{message}</span>}
    </div>
  );
}

C. as a way to delay some kind of action call

const AwesomeForm = ({ onCancel, onComplete }) => {
  const [isActive] = useTimeout(onComplete, { deps: [ onComplete ], duration: 7000 });
  return (
    <fieldset className="awesome-form">
      {isActive && <span>This form will submit after 7 seconds unless you click cancel...</span>}
      <button onClick={onCancel}>Cancel</button>
    </fieldset>
  );
}

useIdleUntilUrgent

React hook that enables easy use of the idle until urgent component loading strategy. This strategy involves fetching resources lazily - either whenever the browser is next idle, or when you request the resources.

Trulsaa/useIdleUntilUrgent

Cannot open pull request to gist

I want to open PR to useLocalStorage() which fixes parse error with "undefined" is stored.
Currently this repository references code of every hooks in gist, where PR cannot open.
I suggest to move the code into this repo, so we can easily track changes and open PR.

Thanks!

Summary Page of Available Hooks

It really good site to sharing the hooks. When it grown, finding a hook shall be a challenge so it would be perfectly if we have a page to summary up all the available hooks

useLocalStorage does not set initial value!

The init value of useLocalStorage is not actually saved to localStorage!

import { useLocalStorage } from 'use-hooks'

export const randomHash = () => Math.random().toString(36).substr(2, 9)

const MyComponent = () => {
  const [persistant, setPersistant] = useLocalStorage('persistant', randomHash())
  console.log(persistant)
}
export default MyComponent

The above will result in a new value every page load. You must set the value manually for it to be saved.

useWindowSize - EsLint error

React Hook useEffect has missing dependencies: 'getSize' and 'isClient'. Either include them or remove the dependency array. (react-hooks/exhaustive-deps)

useMedia Bug

After changing a route (e.g. from '/' to '/items') the following error is thrown:

TypeError: Failed to execute 'removeEventListener' on 'EventTarget': 2 arguments required, but only 1 present.

I'm using CRA 2 and react-router.

useBuildReducer (typescript-typesafe useReducer)

Maybe you're at the point where you accept Typescript-contributions - this can of course be used without typescript, but it really shines with typescript ;)

I've got a prototype of this scetched out here: https://codesandbox.io/s/kx4ml7521o

Essentially, you use it like this:

 const [state, dispatchWithType] = useBuildReducer(
    /* initial state: */ { data: "initial text" }
  )
    // add case/action type with payload definition
    .withCase<"concat", string>("concat", (state, action) => ({
      data: state.data + action.payload
    }))
    // add case/action type without payload
    .withCase("toUpper", state => ({ data: state.data.toUpperCase() }))
    // add case/action type without payload
    .withCase("clear", () => ({ data: "" }))
    .build();

and then you can use it like this:

dispatchWithType(type, payload);

so in this case:

dispatchWithType("concat", "some string");
// or
dispatchWithType("clear");

The nice thing about this is that typescript restricts action types to valid action types - and enforces correct payload types - so it's a typesafe useReducer.

I'm thinking about wrapping the reducers in immer, like redux-starter-kit does, but for now this is only a prototype - I'd like some opinion about this.

useClickOutside

Hook to interact when user click outside a specific DOM element.
Typically, used for closing popin.

function useClickOutside(ref, fn) {
  useEffect(() => {
    document.addEventListener("touchend", handler, true);
    document.addEventListener("click", handler, true);

    return () => {
      document.removeEventListener("touchend", handler, true);
      document.removeEventListener("click", handler, true);
    };
  }, []);

  function handler(e) {
    if (ref && !ref.current.contains(e.target)) {
      fn(e);
    }
  }
}

function App() {
  const ref = React.createRef();

  function clickIt(e) {
    console.warn("CLICK OUTSIDE");
  }

  clickOutside(ref, clickIt);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <div ref={ref}>
        <p style={{background: "blue", width: '100%'}}>polo</p>
      </div>
    </div>
  );
}

useLoadMore

Allows creating a 'load more' button that paginates. In theory, one could build an async version of this pretty easily.

import * as R from "ramda";
import { useState } from "react";

/**
 * Default to displaying only pageSize items, but allow loadMore.
 * @param items Items to return
 * @param getId The serialized ID of the item.
 * @param pageSize Number of items to display per page.
 * @returns [filteredItems, loadMore, hasMore]
 */
function useLoadMore<T>(
  items: T[],
  getId: ((item: T) => string),
  pageSize: number = 5
): [T[], () => void, boolean] {
  const maybeNextId = items[pageSize];
  const [nextId, setNextId] = useState<string | null>(
    maybeNextId ? getId(maybeNextId) : null
  );
  return [
    R.takeWhile(item => getId(item) !== nextId, items),
    () => {
      if (nextId === null) {
        return;
      }
      const nextIndex = items.findIndex(item => getId(item) === nextId);
      const maybeNextPageId = items[nextIndex + pageSize];
      setNextId(maybeNextPageId ? getId(maybeNextPageId) : null);
    },
    !!nextId
  ];
}

export default useLoadMore;

useBrowserHistory

Hey! I just created a new hook which makes use of the browser history state, hope you find this one interesting.

It's main goal is for inside projects that have modals / popups / dialogs, they can easily be hooked into the browser's native history, so they can be closed (and optionally reopened) when the user presses back (or forward) in their browser.

It's a common UX bug I see in many, many websites so I hope this hook can help developers easily fix this issue.

It's especially bad on Android phones when modals don't use the browser history to create a new entry for itself, I find myself losing the page I was on all the time!

Anyway, hope you like this one! Thanks.

https://github.com/zcallan/use-browser-history

import React, { useState } from 'react'

import useBrowserHistory from 'use-browser-history'

function Modal({ isOpen, onClose, onOpen }) {
  const [handleBack] = useBrowserHistory( 'my-modal', isOpen, onClose, onOpen );

  if ( !isOpen )
    return null;

  return (
    <div className="modal">
      <div className="modal-backdrop" onClick={handleBack} />

      <div className="modal-box">
        <p>Hello!</p>
        <button onClick={handleBack}>Close modal</button>
      </div>
    </div>
  )
}

function App() {
  const [isOpen, setIsOpen] = useState( false );

  return (
    <div>
      <button onClick={() => setIsOpen( true )}>Open modal</button>

      <Modal
        isOpen={isOpen}
        onClose={() => setIsOpen( false )}
        onOpen={() => setIsOpen( true )}
      />
    </div>
  );
}

Suggestion - add index to website

Hi,

I noticed that you have a lot of recipes inside the website. I think it will be great if you could add index/table of contents at the top of the website.

Thank you.

license

I would like to clarify the licenses for the hook examples on the site. Since this repository is released under MIT, does MIT license apply to each example? (in which case, we will have to preserve MIT license text when we copy the example code)

useRefArray

/* useRefArray.js */
export default (list) => {
    const ref = React.useRef([]);

    React.useEffect(() => {
        ref.current = ref.current.slice(0, list.length);
    }, [list]);

    const getter = (index) => {
        return (element) => {
            ref.current[index] = element;
        }
    }

    return [ref, getter];
}

/* example.js */
export default ({ someList }) => {
    const [listRef, assignListRef] = useRefArray(someList);
    const comps = someList.map((item, index) => {
        return <div key={index} ref={assignListRef(index)}>{item.someText}</div>
    })
    return <div>{comps}</div>
}

Suggestion: useFocusLock

There are a few component solutions for this but might it be useful to have a hook? Interested to get peoples thoughts. Happy to help out with an example of how this might be done!

Suggestion: useObjectState

If i have more than one state value i prefer to retrieve them from an object. Let me explain myself in code.

const [email, setEmail] = useState('')
const [password, setPassword] = useState('')

So instead adding new useState calls i do like:
const [{email, password}, setState] = useState({email: '', password:''})
But the problem with this is that every time when i want to update one of email or password i should also set previousState. I think I could not gave the idea. Here is the code:

onChangeText={text => setState(prevState => ({ ...prevState, email: text }))}
or again for password
onChangeText={text => setState(prevState => ({ ...prevState, password: text }))}

As you can see i need to write ...prevState

That's why i write useObjectState to fix this.

import { useState } from 'react'

export default (initialState) => {
    const [state, setState] = useState(initialState)
    return [state, state => setState(prevState => ({ ...prevState, ...state }))]
}

const [{email, password}, setState] = useObjectState({ email: '', password: '' })
onChangeText={text => setState({ password: text })}

Update OG image

OG share image still says "one new recipe every day" and we're switching to a more flexible schedule (prob twice a week).

useLazyLoader - rendering large lists

useMergeState

I wanted to make a PR but I don't know how Gatsby works so I figured I can leave the code here and let you decide if you'd like to publish it or not.

The idea is to mimc the functionality of the old setState as closely as possible:

  1. Provide an object to be merged into state OR
  2. Provide a function which gets passed the old state and returns a new object to be merged into state.

To me this is especially helpful in 3 scenarios:

  1. You have a lot of state and don't want to have a ton of useState declarations at the top of your component.
  2. You want to stick with what you're used to from setState.
  3. You want to avoid the overhead of using useReducer.

useMergeState

import { useState } from 'react'


// Object-checking helper fxn since this is only meant to work with objects.
const objCheck = thing => {
  if (({}).toString.call(thing) !== '[object Object]') {
    throw '`useMergeState` only accepts objects.'
  }
}

const useMergeState = (initialState = {}) => {
  objCheck(initialState)
  const [state, setState] = useState(initialState)

  /*
    Just like the old `setState` with React classes, you can pass a fxn to `mergeState`.
    Why would you want to do this? Because certain scenarios, such as using the `useEffect` hook
    create closures around values that may become stale or outdated by the time they get used.
    Providing a fxn ensures that fxn has the latest available state object to work with.
  */
  const mergeState = objOrFxn => {
    // Passing a fxn to `mergeState`.
    if (objOrFxn instanceof Function) {
      setState(prevState => {
        const newState = objOrFxn(prevState)
        objCheck(newState)
        return { ...prevState, ...newState }
      })

    // Passing an object to `mergeState.
    } else {
      objCheck(objOrFxn)
      setState(prevState => ({ ...prevState, ...objOrFxn }))
    }
  }

  return [state, mergeState]
}

Example usage

import React from 'react'


const MyComponent = () => {
  const [state, mergeState] = useMergeState({
    date: new Date(),
    num: 1
  })

  // Using an object.
  const button1Click = () => mergeState({ date: new Date() })
  
  // Using a function.
  const button2Click = () => mergeState(oldState => ({ num: oldState.num + 1 }))

  return (
    <>
      <button onClick={button1Click}>{state.date.toString()}</button>
      <button onClick={button2Click}>{state.num}</button>
    </>
  )
}

useFullscreen

Returns the current fullscreen state, and a toggle function if fullscreen is available and enabled in the browser.

import { useEffect, useState } from 'react';

const doc = document;

const changeEvent = [
  'fullscreenchange',
  'webkitfullscreenchange',
  'mozfullscreenchange',
].find(name => `on${name}` in doc);

const fullscreenEnabled =
  doc.fullscreenEnabled !== false &&
  doc.webkitFullscreenEnabled !== false &&
  doc.mozFullScreenEnabled !== false &&
  changeEvent;

const requestFullscreen = (el = doc.documentElement) => {
  const req = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen;
  if (req) {
    req.call(el);
  }
};

const exitFullscreen = () => {
  const exit = doc.exitFullscreen || doc.webkitExitFullscreen || doc.mozCancelFullScreen;
  if (exit) {
    exit.call(doc);
  }
};

const isBrowserFullscreen = () =>
  !!(
    doc.fullscreenElement ||
    doc.webkitFullscreenElement ||
    doc.mozFullScreenElement ||
    doc.webkitIsFullScreen ||
    doc.mozFullScreen
  );

const toggleFullscreen = el => {
  if (isBrowserFullscreen()) {
    exitFullscreen();
  } else {
    requestFullscreen(el);
  }
};

export default function useFullscreen() {
  const [isFullscreen, setState] = useState(isBrowserFullscreen());
  useEffect(() => {
    if (!fullscreenEnabled) return;
    const handleFullscreenChange = () => setState(isBrowserFullscreen());
    doc.addEventListener(changeEvent, handleFullscreenChange);
    return () => {
      doc.removeEventListener(changeEvent, handleFullscreenChange);
    };
  }, []);
  return [isFullscreen, fullscreenEnabled ? toggleFullscreen : undefined];
}

Edit 34lw4xr141

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.