DEV Community

Cover image for React Hooks Design Pattern
Jonathan Rodriguez
Jonathan Rodriguez

Posted on • Edited on

13 2

React Hooks Design Pattern

I want to share with you one pattern to improve the readability and maintainability of your React components.

Why should we care about maintainability?
If our components are interdependent, not extensible, and not single-responsible, as our application grows in lines of code and complexity, our time to add new features or resolve bugs will also increase.

Let's say we have a form component, and we need to save its values into local storage as it changes.

function LocalStorageForm() {
  const [values, setValues] = useState({});

  const handleChange = (event) => {
    const { name, value } = event.target;
    setValues({ ...values, [name]: value });
  };

  return <Form values={values} onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

We might want to change the code into something like this, adding local storage synchronization logic inside the component:

function MessyLocalStorageForm() {
  const [values, setValues] = useState(() => {
    const storedValues = JSON.parse(localStorage.getItem('form'));
    return storedValues || {};
  });

  const handleChange = (event) => {
    const { name, value } = event.target;
    const updatedValues = { ...values, [name]: value };
    localStorage.setItem("form", JSON.stringify(updatedValues));
    setValues(updatedValues);
  };

  return <Form values={values} onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

It works, but is messy, what if we have another form where we want to also synchronize the values with local storage? Could we abstract the complexity of state management to reuse it multiple times? Yes, creating a custom hook only responsible for the local storage synchronization.

import { useState, useEffect } from "react";

function useLocalStorage(key, initialValue) {
  const [state, setState] = useState(() => {
    const value = localStorage.getItem(key);
    return JSON.parse(value) || initialValue;
  });

  useEffect(() => {
    const value = JSON.stringify(state);
    localStorage.setItem(key, value);
  }, [key, state]);

  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

And now, all we need to do is go back to the first version of our code and just change the useState to our new custom hook useLocalStorage.

function LocalStorageForm() {
  const [values, setValues] = useLocalStorage('form', {});

  const handleChange = (event) => {
    const { name, value } = event.target;
    setValues({ ...values, [name]: value });
  };

  return <Form values={values} onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

Photo by Xavi Cabrera on Unsplash

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay