Categories
React Hooks

Top React Hooks — Data Structures

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.

useMap

The useMap hook lets us track key-value pairs.

To use it, we can write:

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

export default function App() {
  const [map, { set, setAll, remove, reset }] = useMap({
    hello: "world"
  });

  return (
    <div>
      <button onClick={() => set(String(Date.now()), new Date().toString())}>
        Add
      </button>
      <button onClick={() => reset()}>Reset</button>
      <button onClick={() => setAll({ foo: "bar" })}>Set new data</button>
      <button onClick={() => remove("foo")} disabled={!map.foo}>
        Remove 'hello'
      </button>
      <pre>{JSON.stringify(map, null, 2)}</pre>
    </div>
  );
}

The useMap hook takes an object and returns an array that has the state object and another object with methods to let us modify the state object.

map has the map state object itself

set takes a key and value as arguments and put them into map .

setAll lets overwrite the existing value of map with another one.

remove lets us remove a property with a given key from map .

reset will reset the state object to the initial value, which is what we passed into the useMap hook.

useSet

The useSet hook lets us get and manipulate a set.

We can add things if they don’t exist.

For instance, we can write:

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

export default function App() {
  const [set, { add, has, remove, toggle, reset }] = useSet(new Set(["bar"]));

  return (
    <div>
      <button onClick={() => add(String(Date.now()))}>Add</button>
      <button onClick={() => reset()}>Reset</button>
      <button onClick={() => remove("foo")} disabled={!has("foo")}>
        Remove 'hello'
      </button>
      <button onClick={() => toggle("foo")}>toggle foo</button>
      <pre>{JSON.stringify([...set], null, 2)}</pre>
    </div>
  );
}

We have the useSet hook with a set passed in to set the initial value of the returned set.

It returns an array with 2 entries.

The first is the set , which is the set itself.

The 2nd is an object with various methods to change the set.

add lets us add an item to the set.

has lets us check whether something is in the set.

remove lets us remove an item from the set.

toggle lets us toggle on an off an item in the set.

reset resets the set to the initial value.

useQueue

We can use the useQueue hook to create a simple FIFO queue.

For example, we can write:

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

export default function App() {
  const { add, remove, first, last, size } = useQueue();

  return (
    <div>
      <ul>
        <li>first: {first}</li>
        <li>last: {last}</li>
        <li>size: {size}</li>
      </ul>
      <button onClick={() => add(Math.random())}>Add</button>
      <button onClick={() => remove()}>Remove</button>
    </div>
  );
}

to create a queue and use it.

The useQueue hook returns an object with various properties.

The add function lets us add an entry to the queue.

remove lets us remove the last entry from the queue.

first returns the first entry of the queue.

last returns the last entry of the queue.

size returns the size of the queue.

Conclusion

React-use lets us create states with various data structures, including maps, sets, and queues.

Categories
React Hooks

Top React Hooks — Vibration, Videos, and Intervals

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.

useVibrate

The useVibrate hook lets us vibrate our device on any device that’s capable of this.

For instance, we can use it by writing:

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

export default function App() {
  const [vibrating, toggleVibrating] = useToggle(false);

  useVibrate(vibrating, [360, 120, 260, 110, 1420, 300], false);

  return (
    <div>
      <button onClick={toggleVibrating}>
        {vibrating ? "Stop" : "Vibrate"}
      </button>
    </div>
  );
}

We have the useToggle hook to toggle the vibration.

The useVibrate hook takes the vibrating state that we created earlier.

The array has the array with the magnitude of the vibrations in each entry.

The 3rd argument indicates whether we want to loop or not.

useVideo

The useVideo hook lets us create a video element with controls.

To use it, we write:

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

export default function App() {
  const [video, state, controls, ref] = useVideo(
    <video
      src="https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4"
      autoPlay
    />
  );

  return (
    <div>
      <pre>{JSON.stringify(state, null, 2)}</pre>
      <button onClick={controls.pause}>Pause</button>
      <button onClick={controls.play}>Play</button>
      <button onClick={controls.mute}>Mute</button>
      <button onClick={controls.unmute}>Un-mute</button>
      <button onClick={() => controls.volume(0.1)}>Volume: 10%</button>
      <button onClick={() => controls.volume(0.5)}>Volume: 50%</button>
      <button onClick={() => controls.volume(1)}>Volume: 100%</button>
      <button onClick={() => controls.seek(state.time - 5)}>-5 sec</button>
      <button onClick={() => controls.seek(state.time + 5)}>+5 sec</button>
      {video}
    </div>
  );
}

to use the hook.

The useVideo takes a component for rendering the video.

And it returns an array with various variables.

video has the video player component itself.

state has the video playing state.

The state has the time which is the time that the video is at.

duration has the duration of the video.

paused indicates whether the video is paused or not.

muted indicates whether the video is muted or not.

controls has the method to let us control the video.

useRaf

The useRaf hook lets us force a component to render on each requestAnimationFrame .

It returns the percentage of time elapsed.

To use it, we can write:

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

export default function App() {
  const elapsed = useRaf(15000, 1000);

  return <div>Elapsed: {elapsed}</div>;
}

We have the useRaf hook with 2 arguments.

The first is the animation duration.

The 2nd is the delay after which to start re-rendering the component.

They’re both in milliseconds.

useInterval

The useInterval hook lets us run a piece of code periodically.

To use it, we can write:

import React from "react";
import { useInterval, useBoolean } from "react-use";

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

  useInterval(
    () => {
      setCount(count + 1);
    },
    isRunning ? 1000 : null
  );

  return (
    <div>
      <h1>count: {count}</h1>
      <div>
        <button onClick={toggleIsRunning}>
          {isRunning ? "stop" : "start"}
        </button>
      </div>
    </div>
  );
}

We use the useInterval hook with 2 arguments.

The callback that runs periodically is the first argument.

The 2nd argument is the length between each callback call.

If it’s null , then the callback isn’t run.

Conclusion

The react-use library lets us run code periodically, re-render during each requestAnimationFrame call, vibrate our device, and display videos.

Categories
React Hooks

Top React Hooks — Update 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.

useUnmount

The useUnmount hook lets us call a function when the component will unmount.

For instance, we can use it by writing:

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

export default function App() {
  useUnmount(() => console.log("umounted"));

  return <div />;
}

The callback we pass into the hook is run when the component is unmounted.

useUpdateEffect

The useUpdateEffect hook lets us run code after the component is mounted.

The signature is the same as the useEffect hook.

For instance, we can write:

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

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

  React.useEffect(() => {
    const interval = setInterval(() => {
      setCount(count => count + 1);
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, []);

  useUpdateEffect(() => {
    console.log("count", count);

    return () => {
      // ...
    };
  }, [count]);

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

We have the setInterval call in the useEffect callback.

It returns a timer so that we can call clearInterval to clear it in the function the callback returns.

The useUpdateEffect hook runs when count updates.

This means that the console log only logs the value when the component state or props updates.

We pass in an array with the values to watch for and run the callback.

useIsomorphicLayoutEffect

The useIsomorphicLayoutEffect hook is a version of the useLayoutEffect hook that doesn’t show warnings when running in a server-side rendered app.

For instance, we can write:

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

export default function App() {
  const [value] = React.useState(1);

  useIsomorphicLayoutEffect(() => {
    window.console.log(value);
  }, [value]);

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

useDeepCompareEffect

The useDeepCompareEffect hook is an alternate version of the useEffect hook that does deep comparisons to determine whether the callback should be run.

For instance, we can write:

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

export default function App() {
  const [count, { inc }] = useCounter(0);
  const [options, setOptions] = React.useState({ step: 5 });

  useDeepCompareEffect(() => {
    inc(options.step);
  }, [options]);

  return (
    <div>
      <button onClick={() => setOptions(({ step }) => ({ step: step + 1 }))}>
        increment
      </button>
      <p>{count}</p>
    </div>
  );
}

We use the useDeepCompareEffect hook to watch for changes in the options state.

It’s an object, so we can use this hook to watch for changes and run the callback if needed instead of using useEffect .

In the callback, we call inc to increase the count state by the option.step value.

useShallowCompareEffect

The useShallowCompareEffect hook will do shallow comparison instead on each dependency instead of checking for reference equality when determining when to run the callback.

For instance, we can write:

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

export default function App() {
  const [count, { inc }] = useCounter(0);
  const [options, setOptions] = React.useState({ step: 5 });

  useShallowCompareEffect(() => {
    inc(options.step);
  }, [options]);

  return (
    <div>
      <button onClick={() => setOptions(({ step }) => ({ step: step + 1 }))}>
        increment
      </button>
      <p>{count}</p>
    </div>
  );
}

We pass in the options array to run the callback we passed into useShallowCompareEffect when it changes.

The rest of the code is the same as the previous example.

Conclusion

The react-use library have hooks that aren’t available in React itself, including varieties of useEffect .

Categories
React Hooks

Top React Hooks — Side Effects and Shared Data

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.

useCustomCompareEffect

We can use the useCustomCompareEffect hook to let us run a callback after comparing the previous and current value our way.

For instance, we can write:

import React from "react";
import { useCustomCompareEffect, useCounter } from "react-use";
import isEqual from "lodash/isEqual";

export default function App() {
  const [count, { inc }] = useCounter(0);
  const [options, setOptions] = React.useState({ step: 5 });

  useCustomCompareEffect(
    () => {
      inc(options.step);
    },
    [options],
    (prevDeps, nextDeps) => isEqual(prevDeps, nextDeps)
  );

  return (
    <div>
      <button onClick={() => setOptions(({ step }) => ({ step: step + 1 }))}>
        increment
      </button>
      <p>{count}</p>
    </div>
  );
}

The useCustomCompareEffect hook takes the 3rd argument with a function to compare the previous and current values of the dependency.

createReducer

We can use the createReducer function to create a store that we can use with our component.

For instance, we can write:

import React from "react";
import { createReducer } from "react-use";
import logger from "redux-logger";

const initialCount = 0;

const useReducer = createReducer(logger);

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    case "reset":
      return { count: action.payload };
    default:
      throw new Error();
  }
}

export default function App() {
  const [state, dispatch] = useReducer(reducer, { count: initialCount });

  return (
    <div>
      <p>count: {state.count}</p>
      <button
        onClick={() =>
          dispatch({ type: "reset", payload: { count: initialCount } })
        }
      >
        reset
      </button>
      <button onClick={() => dispatch({ type: "increment" })}>increment</button>
      <button onClick={() => dispatch({ type: "decrement" })}>decrement</button>
    </div>
  );
}

We have a reducer function that’s like a redux reducer.

It takes an action object that we can use to set the state.

The createReducer function takes middleware made for Redux and returns the useReducer hook.

The hook takes our reducer and the initial state.

It then returns an array with the state and dispatch variables.

state has the store state.

dispatch lets us dispatch actions to the store.

createReducerContext

The createReducerContext function returns a React context hook that acts like useReducer except that the state is shared between all components in the provider.

For example, we can write:

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

const initialCount = 0;

const reducer = (state, action) => {
  switch (action) {
    case "increment":
      return state + 1;
    case "decrement":
      return state - 1;
    default:
      throw new Error();
  }
};

const [useSharedCounter, SharedCounterProvider] = createReducerContext(
  reducer,
  0
);

const CounterA = () => {
  const [count, dispatch] = useSharedCounter();

return (
    <div>
      <p>count: {count}</p>
      <button onClick={() => dispatch("increment")}>increment</button>
      <button onClick={() => dispatch("decrement")}>decrement</button>
    </div>
  );
};

const CounterB = () => {
  const [count, dispatch] = useSharedCounter();

  return (
    <div>
      <p>count: {count}</p>
      <button onClick={() => dispatch("increment")}>increment</button>
      <button onClick={() => dispatch("decrement")}>decrement</button>
    </div>
  );
};

export default function App() {
  return (
    <SharedCounterProvider>
      <CounterA />
      <CounterB />
    </SharedCounterProvider>
  );
}

We used the createReducerContext function to return a SharedCounterProvider .

It takes the reducer and the initial state as the arguments in that order.

This way, we can use the same state across all the components inside the context component.

The useSharedCounter hook lets us get and set the state.

dispatch lets us dispatch our actions to the store.

count has the state.

Conclusion

The react-use library lets us commit side effects in various ways.

It also has hooks to let us share data app-wide.

Categories
React Hooks

Top React Hooks — Shared Data and Default States

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.

createStateContext

The createStateContext function is a function to create React context hooks.

It acts like useState but the state can be shared with all components in the provider.

For example, we can use it by writing:

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

const [useSharedText, SharedTextProvider] = createStateContext("");

const InputA = () => {
  const [text, setText] = useSharedText();
  return (
    <p>
      <input
        type="text"
        value={text}
        onInput={ev => setText(ev.target.value)}
      />
    </p>
  );
};

const InputB = () => {
  const [text, setText] = useSharedText();
  return (
    <p>
      <input
        type="text"
        value={text}
        onInput={ev => setText(ev.target.value)}
      />
    </p>
  );
};

export default function App() {
  return (
    <SharedTextProvider>
      <InputA />
      <InputB />
    </SharedTextProvider>
  );
}

We called createStateContext to create the context and hook to use the context.

Then we created 2 components that use the useSharedText hook to get and set the shared state.

The SharedTextProvider is used by wrapping around the components that use the useSharedText hook so we can use the state in both components.

The provider takes the initialValue prop to let us set the initial value of the shared state.

We can write:

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

const [useSharedText, SharedTextProvider] = createStateContext("");

const InputA = () => {
  const [text, setText] = useSharedText();
  return (
    <p>
      <input
        type="text"
        value={text}
        onInput={ev => setText(ev.target.value)}
      />
    </p>
  );
};

const InputB = () => {
  const [text, setText] = useSharedText();
  return (
    <p>
      <input
        type="text"
        value={text}
        onInput={ev => setText(ev.target.value)}
      />
    </p>
  );
};

export default function App() {
  return (
    <SharedTextProvider initialValue="abc">
      <InputA />
      <InputB />
    </SharedTextProvider>
  );
}

to use it.

Then we’ll see ‘abc’ in both components.

useDefault

The useDefault hook returns the default when the state is null or undefined .

For instance, we can write:

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

export default function App() {
  const initialUser = { name: "james" };
  const defaultUser = { name: "mary" };
  const [user, setUser] = useDefault(defaultUser, initialUser);

  return (
    <div>
      <div>User: {user.name}</div>
      <input onChange={e => setUser({ name: e.target.value })} />
      <button onClick={() => setUser(null)}>set to null</button>
    </div>
  );
}

to use the useDefault hook.

The first argument is used for the default value.

It’ll be the value of user when we set it to null .

The initialUser is set as the value of user when our component mounts.

When we type in something, then the user will be replaced with what’s typed in.

useGetSet

The useGetSet hook lets us get and set a state value.

For instance, we can write:

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

export default function App() {
  const [get, set] = useGetSet(0);
  const onClick = () => {
    set(get() + 1);
  };

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

The useGetSet hook takes an initial value.

And it returns with the get and set functions to get and set the state data respectively.

Conclusion

The react-use library lets us create a context to share data and get and set data in various ways.