DEV Community

Cover image for 4 custom react hooks that will make your development easier
Abdullah Furkan Özbek
Abdullah Furkan Özbek

Posted on • Originally published at blog.furkanozbek.com

4 custom react hooks that will make your development easier

1. useToggle

Basically, what this hook does is that, it takes a 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.
// Hook
// Parameter is the boolean, with default "false" value
const useToggle = (initialState = false) => {
    // Initialize the state
    const [state, setState] = useState(initialState);

    // Define and memorize toggler function in case we pass down the comopnent,
    // This function change the boolean value to it's opposite value
    const toggle = useCallback(() => setState(state => !state), []);

    return [state, toggle]
}

// Usage
function App() {
    // Call the hook which returns, current value and the toggler function
    const [isTextChanged, setIsTextChanged] = useToggle();

    return (
      <button onClick={setIsTextChanged}>
                {isTextChanged ? 'Toggled' : 'Click to Toggle'}
            </button>
    );
}
Enter fullscreen mode Exit fullscreen mode

2. useOnClickOutside

This hook allows you to detect clicks outside of a specified element.

By abstracting this logic out into a hook we can easily use it across all of our components that need this kind of functionality.

For Example;

  • dropdown menus,
  • tooltips,
  • modals
  • etc..
// Hook
const useOnClickOutside = (ref, handler) => {
  useEffect(
    () => {
      const listener = (event) => {
        // Do nothing if clicking ref's element or descendent elements
        if (!ref.current || ref.current.contains(event.target)) {
          return;
        }
        handler(event);
      };
      document.addEventListener("mousedown", listener);
      document.addEventListener("touchstart", listener);
      return () => {
        document.removeEventListener("mousedown", listener);
        document.removeEventListener("touchstart", listener);
      };
    },

    [ref, handler]
  );
}
Enter fullscreen mode Exit fullscreen mode
// Usage
function App() {
  // Create a ref that we add to the element for which we want to detect outside clicks
  const ref = useRef();
  // State for our modal
  const [isModalOpen, setModalOpen] = useState(false);
  // Call hook passing in the ref and a function to call on outside click
  useOnClickOutside(ref, () => setModalOpen(false));
  return (
    <div>
      {isModalOpen ? (
        <div ref={ref}>
          👋 Hey, I'm a modal. Click anywhere outside of me to close.
        </div>
      ) : (
        <button onClick={() => setModalOpen(true)}>Open Modal</button>
      )}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. useSubmit

Instead of recreating loading and form states we can also move that logic inside a hook called useSubmit

// Hook
const useSubmit = submitFunction => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

    const handleSubmit = async () => {
    try {
      setLoading(true);
      setError(null);
      await submitFunction();
    } catch (error) {
      setError(error);
    } finally {
      setLoading(false);
    }
  };

  return [handleSubmit, loading, error];
};
Enter fullscreen mode Exit fullscreen mode
// Usage
function App() {
    const mySubmitFunction = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
                resolve("Timeout Finished")
        }, 2000);
      });
    };
    const [handleSubmit, loading, error] = useSubmit(mySubmitFunction);

    return (
        <div className="App">
          <button onClick={handleSubmit} disabled={loading}>
            {!loading ? "Click me" : "Loading..."}
          </button>
          {error && <div>{error}</div>}
        </div>
      );
}
Enter fullscreen mode Exit fullscreen mode

4. useMediaQuery

If you want to write css in js or you just want to add some sideEffect to the specific device or breakpoint this hook is for you.

// Hook
const useMediaQuery = (query = "(min-width: 576px)") => {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) {
      setMatches(media.matches);
    }
    const listener = () => {
      setMatches(media.matches);
    };
    media.addListener(listener);
    return () => media.removeListener(listener);
  }, [matches, query]);

  return matches;
}

// Usage
const isTablet = useMediaQuery("(max-width: 1200px)");
Enter fullscreen mode Exit fullscreen mode

Links

Top comments (0)