How to encapsulate useState of components in react?

Viewed 212

I have the following example code:

export function SomeFormComponent() {
    const [alertMessage, setAlertMessage] = useState("");
    const [alertTitle, setAlertTitle] = useState("");
    const [alertSeverity, setAlertSeverity] = useState("");


    //to be called at the result of form result
    const setAlert = (title, message, severity) => {
        setAlertTitle(title);
        setAlertMessage(message);
        setAlertSeverity(severity);
    }

    return (<div>
        <FormContents/>
        <Alert severity={alertSeverity}>
          <AlertTitle>{alertTitle}</AlertTitle>
          {alertMessage}
        </Alert>
    </div>)
}

It is a form with an alert component, where the result of a fetch is shown. My problem is that I duplicate this code (useState(), setAlert(), ) in each form that my application has. I want to know if there a way to do this without duplicating code.

2 Answers

Create a custom hook, and an accompanying component. The hook provides a setAlert() function, and an alert object that you can spread on the component.

useAlert custom hook - you only need a single setState with an object that includes all the values:

const useAlert = () => {
  const [alert, setAlert] = useState({ alertMessage: '', alertTitle: '', alertSeverity: '' });
  
  return [
    alert,
    (alertMessage, alertTitle, alertSeverity) => {
      setAlert({ alertMessage, alertTitle, alertSeverity });
    }     
  ]
}

AlertWrapper component:

const AlertWrapper = ({ alertSeverity, alertTitle, alertMessage }) => (
  <Alert severity={alertSeverity}>
    <AlertTitle>{alertTitle}</AlertTitle>
    {alertMessage}
  </Alert>
);

Usage:

export function SomeFormComponent() {
  const [alert, setAlert] = useAlert();

  // use setAlert in your form
  return (
    <div>
      <FormContents/>
      <AlertWrapper {...alert} />
    </div>
  );
}

You can have a customHook .

const useAlert = () => {
  const [alertMessage, setAlertMessage] = useState();
  const [alertTitle, setAlertTitle] = useState("");
  const [alertSeverity, setAlertSeverity] = useState("");


  const setAlert = (title, message, severity) => {
      setAlertTitle(title);
      setAlertMessage(message);
      setAlertSeverity(severity);
  }

  return [ alertMessage, alertTitle, alertSeverity, setAlert]
}


export function SomeFormComponent() {
  const [ message, title, severity, setAlert ] = useAlert();

  return (<div>
      <FormContents/>
      <Alert severity={severity}>
        <AlertTitle>{title}</AlertTitle>
        {message}
      </Alert>
  </div>)
}
Related