Categories
React Hooks

Top React Hooks — Memoization and Previous Value

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

react-use

The react-use library is a big library with many handy hooks.

createMemo

The createMemo function creates a hook that has the state memoized.

Ir takes a function that returns a state.

For instance, we can write:

import React from "react";
import { createMemo } from "react-use";

const product = n => {
  let result = 1;
  for (let i = 1; i <= n; i++) {
    result *= i;
  }
  return result;
};

const useMemoProduct = createMemo(product);

export default function App() {
  const result = useMemoProduct(9);

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

We have the product function which returns the product of n numbers multiplied together.

And we pass that into the createMemo function to return the useMemoProduct hook.

The hook takes the same arguments as the product function.

The hook returns the result which is the same as the product function.

Then we render the result in App .

useGetSetState

The useGetSetState hook lets us get and set the state, where the state may be an object.

To use it, we can write:

import React from "react";
import { useGetSetState } from "react-use";

export default function App() {
  const [get, setState] = useGetSetState({ count: 0 });
  const onClick = () => {
    setState({ count: get().count + 1 });
  };

  return <button onClick={onClick}>Clicked: {get().count}</button>;
}

We call the useGetSetState with an argument being the initial value.

It returns the get function to get the state value.

The setState the function sets the state.

Then we can call get to get the count property’s value.

usePrevious

We can get the previous value of a state with the usePrevious hook.

For instance, we can write:

import React from "react";
import { usePrevious } from "react-use";

export default function App() {
  const [count, setCount] = React.useState(0);
  const prevCount = usePrevious(count);

  return (
    <p>
      <button onClick={() => setCount(count + 1)}>increment</button>
      <button onClick={() => setCount(count - 1)}>decrement</button>
      <p>
        Now: {count}, before: {prevCount}
      </p>
    </p>
  );
}

We use the useState hook to return a state getter and setter function.

Then we pass the state into the usePrevious hook.

And then we get the current and previous value of count with count and prevCount respectively.

usePreviousDistinct

The usePreviousDistinct hook is like usePrevious , but the value updates only when the value actually changes.

This lets us get the previous distinct value instead of the previous value.

For instance, we can write:

import React from "react";
import { usePreviousDistinct, useCounter } from "react-use";

export default function App() {
  const [count, { inc: relatedInc }] = useCounter(0);
  const [anotherCount, { inc }] = useCounter(0);
  const prevCount = usePreviousDistinct(count);

  return (
    <p>
      Count: {count}, before count: {prevCount}
      <button onClick={() => relatedInc()}>Increment</button>
      Another count: {anotherCount}
      <button onClick={() => inc()}>Increment Unrelated</button>
    </p>
  );
}

We created 2 number states, count and anotherCount .

Then we use the increment functions that are returned with them.

And we pass the count into the usePreviousDistinct hook.

Conclusion

The react-use library lets us memoize results, get the previous value, and more with its hooks.

Categories
React Hooks

Top React Hooks — Long Press and Mouse Position

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

react-use

The react-use library is a big library with many handy hooks.

The useLongPress hook lets us detect long presses of a key.

To use it, we can write:

import React from "react";
import { useLongPress } from "react-use";

export default function App() {
  const onLongPress = () => {
    console.log("long pressed");
  };

  const defaultOptions = {
    isPreventDefault: true,
    delay: 300
  };
  const longPressEvent = useLongPress(onLongPress, defaultOptions);

  return <button {...longPressEvent}>long press me</button>;
}

We have the useLongPress hook that takes a callback to run when the button us long pressed.

defaultOptions has the options for the hook.

isPreventDefault lets us prevent the default action.

delay is the delay before running the callback.

We pass the object that’s returned by the hook to the button.

The longPressEvent object has various event handlers, including onMouseDown , onTouchStart , onMouseUp , onMouseLeave and onTouchEnd .

The useMedia hook lets us detect the given media query in our React component.

To use it, we run:

import React from "react";
import { useMedia } from "react-use";

export default function App() {
  const isWide = useMedia("(min-width: 400px)");

  return <div>Screen is wide: {isWide ? "Yes" : "No"}</div>;
}

We use the useMedia hook with the media query we want to watch for in our component.

It returns a boolean that indicates whether the given media query is matched.

The useMediaDevices hook lets us track connected hardware devices.

For instance, we can use it by writing:

import React from "react";
import { useMediaDevices } from "react-use";

export default function App() {
  const state = useMediaDevices();

  return <pre>{JSON.stringify(state, null, 2)}</pre>;
}

The useMediaDevices hook returns an object with the devices property, which has the deviceId , groupId , kind , and label properties.

kind has the hardware type.

The useMotion hook lets us detect motion with the acceleration sensor.

For instance, we can write:

import React from "react";
import { useMotion } from "react-use";

export default function App() {
  const state = useMotion();

  return <pre>{JSON.stringify(state, null, 2)}</pre>;
}

We have the useMotion hook to return the data from the accelerometer.

It includes the acceleration , accelerationIncludingGravity , rotationRate , and interval .

They give us the acceleration and rotation rate of our device.

The useMouse lets us re-render on mouse position changes.

For instance, we can use it by writing:

import React from "react";
import { useMouse } from "react-use";

export default function App() {
  const ref = React.useRef(null);
  const mouseLocation = useMouse(ref);

  return (
    <div ref={ref}>
      <div>{JSON.stringify(mouseLocation)}</div>
    </div>
  );
}

The useMouse hook takes a ref for the element that we want to watch the mouse position for.

docX and docY has the mouse position in the whole document.

posX and posY has the position in the element.

elX and elY has the mouse position in the element.

elH and elW has the height and width of the element.

Conclusion

react-use has hooks to detect long mouse presses and mouse positions.

Categories
React Hooks

Top React Hooks — Lock Scrolling, Animation Loop, Session Storage, and Throttling

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

react-use

The react-use library is a big library with many handy hooks.

useLockBodyScroll

The useLockBodyScroll hook lets us lock the scrolling of the body element.

It’s useful for modals and overlays.

It takes an argument to let us lock scrolling or not.

For example, we can write:

import React from "react";
import { useLockBodyScroll, useToggle } from "react-use";

export default function App() {
  const [locked, toggleLocked] = useToggle(false);

  useLockBodyScroll(locked);

  return (
    <div>
      <button onClick={() => toggleLocked()}>
        {locked ? "Unlock" : "Lock"}
      </button>
      {Array(1000)
        .fill()
        .map((_, i) => (
          <p>{i}</p>
        ))}
    </div>
  );
}

We have a button to toggle the locked state.

If it’s true , we disable locking scrolling on the body.

Otherwise, we let users scroll the body.

useRafLoop

The useRafLoop hook lets us run the requestAnimationFrame loop without re-rendering the parent component.

The loop stops automatically on component unmount.

For instance, we can write:

import React from "react";
import { useRafLoop, useUpdate } from "react-use";

export default function App() {
  const [ticks, setTicks] = React.useState(0);
  const [lastCall, setLastCall] = React.useState(0);
  const update = useUpdate();

  const [loopStop, loopStart, isActive] = useRafLoop(time => {
    setTicks(ticks => ticks + 1);
    setLastCall(time);
  });

  return (
    <div>
      <div>RAF triggered: {ticks} (times)</div>
      <div>Last high res timestamp: {lastCall}</div>
      <br />
      <button
        onClick={() => {
          isActive() ? loopStop() : loopStart();
          update();
        }}
      >
        {isActive() ? "stop" : "start"}
      </button>
    </div>
  );
}

We use the useRafLoop hook by passing in callback with the time , which is the timestamp since the loop started.

The timestamp is in milliseconds.

It returns an array with the loopStop , loopStart and isActive variables.

loopStop lets us stop the requestAnimationFrame loop.

loopStart lets us start the requestAnimationFrame loop.

isActive is true when the requestAnimationFrame loop is active.

useSessionStorage

The useSessionStorage hook lets us manage our browser’s session storage.

To use it, we write:

import React from "react";
import { useSessionStorage } from "react-use";

export default function App() {
  const [value, setValue] = useSessionStorage("session-key", "foo");

  return (
    <div>
      <div>Value: {value}</div>
      <button onClick={() => setValue("qux")}>qux</button>
      <button onClick={() => setValue("baz")}>baz</button>
    </div>
  );
}

The useSessionStorage hook takes the key for the session storage as the first argument.

The 2nd argument is the value for the given key.

It returns the value and setValue variables to let us get and set the value respectively.

useThrottle

We can use the useThrottle hook to throttle the value updates.

To use it, we can write:

import React from "react";
import { useThrottle } from "react-use";

export default function App() {
  const [value, setValue] = React.useState(0);
  const throttledValue = useThrottle(value, 1000);

  return (
    <>
      <button onClick={() => setValue(c => c + 1)}>increment</button>
      <div>Value: {value}</div>
      <div>Throttled value: {throttledValue}</div>
    </>
  );
}

We call the useThrottle hook, which takes the state value and the number of milliseconds to delay the updates.

Then we render both the unthrottled and throttled values.

Conclusion

We can throttle state updates, lock scrolling, run the requestAnimationFrame loop, and manage session storage with the react-use library.

Categories
React Hooks

Top React Hooks — Lifecycle Hooks

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

react-use

The react-use library is a big library with many handy hooks.

useMountedState

The useMountedState hook lets us check a component’s mount state.

It returns a function that returns true is it’s mounted and false if it’s not.

For instance, we can write:

import React from "react";
import { useMountedState } from "react-use";

export default function App() {
  const isMounted = useMountedState();

  return <div>{isMounted() ? "mounted" : "not mounted"}</div>;
}

We can just use the returned value to check if the component is mounted.

useUnmountPromise

The useUnmountPromise hook lets us check the mounted state with a promise.

The promise doesn’t resolve if the component unmounts.

For instance, we can write:

import React from "react";
import useUnmountPromise from "react-use/lib/useUnmountPromise";

export default function App() {
  const mounted = useUnmountPromise();

  const callback = async () => {
    await mounted(Promise.resolve(1));
  };

  React.useEffect(callback, []);

  return <div />;
}

We pass in a promise to the mounted function that runs when the component is mounted.

It also takes an error callback than runs when the component is unmounted.

usePromise

The usePromise hook returns a helper function that wraps promises.

Promises in the function only resolves when the component is mounted.

For instance, we can write:

import React from "react";
import { usePromise } from "react-use";

export default function App() {
  const mounted = usePromise();
  const [value, setValue] = React.useState();

  const onMount = async () => {
    const value = await mounted(Promise.resolve(1));
    setValue(value);
  };

  React.useEffect(() => {
    onMount();
  });

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

We call the usePromise hook to return the mounted function.

The mounted function takes a promise and returns a promise that resolves to the value of the promise we passed to it.

Then we can use the resolved value however we like.

useLogger

The useLogger lets us logs component transitions.

To use it, we can write:

import React from "react";
import { useLogger } from "react-use";

const Counter = props => {
  useLogger("Counter", props);
  return props.count;
};

export default function App() {
  const [count, setCount] = React.useState(0);

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>increment</button>
      <p>
        <Counter count={count} />
      </p>
    </div>
  );
}

We have the Counter prop that has the useLogger hook.

It takes the props from the component and logs it.

Then when we pass values to the count prop, they’ll all be logged.

useMount

The useMount hook lets us call a function after the component is mounted.

To use it, we can write:

import React from "react";
import { useMount } from "react-use";

export default function App() {
  useMount(() => console.log("mounted"));

 return <div />;
}

to use it.

We just pass in a callback that runs when the component is mounted.

Conclusion

The react-use library provides us with lifecycle hooks for running code on mount, unmount, and log the values.

Categories
React Hooks

Top React Hooks — Keypresses and Intersection

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

react-use

The react-use library is a big library with many handy hooks.

We can use the useIntersection hook to detect whether an element is obscured or fully in view.

To use it, we can write:

import React from "react";
import { useIntersection } from "react-use";

export default function App() {
  const intersectionRef = React.useRef(null);
  const intersection = useIntersection(intersectionRef, {
    root: null,
    rootMargin: "0px",
    threshold: 1
  });

  return (
    <>
      {Array(50)
        .fill()
        .map((_, i) => (
          <p>{i}</p>
        ))}
      <div ref={intersectionRef}>
        {intersection && intersection.intersectionRatio < 1
          ? "Obscured"
          : "Fully in view"}
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. In varius
          nisl quis nibh laoreet, vitae feugiat nisi maximus. Nullam vitae mi
          magna. Fusce lorem lacus,
        </p>
      </div>
    </>
  );
}

We created a ref that we pass into the useIntersection hook and the element that we want to watch.

The hook takes a few options.

root is the root element.

rootMargin is the margin of the root.

threshold is the threshold to determine whether the intersection exists.

The useKey hook lets us run a handler when a keyboard key is pressed.

For instance, we can write:

import React from "react";
import { useKey } from "react-use";

export default function App() {
  const [count, set] = React.useState(0);
  const increment = () => set(count => count + 1);
  useKey("ArrowDown", increment);

  return <div>Press arrow down: {count}</div>;
}

We use the useKey hook with the string with the key name and the function to run when the key is pressed.

It’s also available as a render prop.

To use it, we write:

import React from "react";
import UseKey from "react-use/lib/comps/UseKey";

export default function App() {
  const [count, set] = React.useState(0);
  const increment = () => set(count => count + 1);

  return (
    <>
      <UseKey filter="ArrowDown" fn={increment} />
      <div>Press arrow down: {count}</div>
    </>
  );
}

We used the UseKey component with the filter and fn props.

filter has the key name.

fn has the function to run when the key is pressed.

We can also use the useKey hook with a predicate:

import React from "react";
import { useKey } from "react-use";

export default function App() {
  const [count, set] = React.useState(0);
  const increment = () => set(count => count + 1);

  const predicate = event => event.key === "ArrowDown";
  useKey(predicate, increment, { event: "keyup" });

  return (
    <>
      <div>Press arrow down: {count}</div>
    </>
  );
}

We have the predicate function to check the key property with the string of the key name.

We pass that into the useKey hook with the object with the event name.

The useKeyPress hook lets us listen for key presses.

For instance, we can write:

import React from "react";
import { useKeyPress } from "react-use";
const keys = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];

export default function App() {
  const states = [];
  for (const key of keys) states.push(useKeyPress(key)[0]);

  return (
    <div>
      Try pressing numbers
      <br />
      {states.join(", ")}
    </div>
  );
}

We have the useKeyPress hook with the argument being the key name.

This will let us detect whether the given key is pressed.

It returns an array with the first entry being true if the key is pressed.

Conclusion

The react-use package has hooks to detect key presses and detect intersections.