DEV Community

Cover image for Facory pattern with React Hooks
Mohan
Mohan

Posted on • Originally published at Medium

Facory pattern with React Hooks

So many times in Application development we face the challenge of reducing redundancy i.e. almost same layout is duplicated across many areas in our code base that only differ by their business logic and not that much in how they look.

Example:

Let’s say we have three different pages sharing the same layout but different business logic

// screen 1
const Multiplication = (props) => {
  const { a, b } = props.url.query;

  return (
    <div>
      <ComplexLayout>
        Multiplication is : ${a * b}
      </ComplexLayout>
    </div>
  );
};

// screen 2
const Subtraction = (props) => {
  const { a, b } = props.url.query;

  return (
    <div>
      <ComplexLayout>
         Subtraction is : ${a - b}
      </ComplexLayout>
    </div>
  );
};

// screen 3
const Addition = (props) => {
  const { a, b } = props.url.query;

  return (
    <div>
      <ComplexLayout>
        Addition is : ${a + b}
      </ComplexLayout>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

In our case we have Multiplication, Subtraction and Addition 3 react components representing different screens that share the same layout design but differ in business logic. For the sake of simplicity we have only 3 components. But in real life projects their number could grow very large very fast.

The problem is it’s redundant and not to mention hard to maintain (If we want to change this layout everywhere we will have to make the same changes in all those places)

So what’s the problem? We can just make the repeating layout as a separate higher order component accepting all the business related stuff.

const useMultiplication = (props) => {
  const { a, b } = props.url.query;
  const label = "Multiplication is :";
  const value = a * b;
  return {label, value}
}

const CommonLayout = (props: {label, value}) => {
  return (
      <div>
        <ComplexLayout>
          {label} : {value}
        </ComplexLayout>
      </div>
  );
}

// screen 1
const Multiplication = (props) => {
  const logic = useMultiplication(props)

  return <CommonLayout {...logic } />
};

// screen 2
const Subtraction = (props) => {
  // we can implement it just like useMultiplication
  const logic = useSubtraction(props) 

  return <CommonLayout {...logic } />
};

// screen 3
const Addition = (props) => {
  // we can implement it just like useMultiplication
  const logic = useAddition(props)

  return <CommonLayout {...logic } />
};

Enter fullscreen mode Exit fullscreen mode

Yup! that might just work for the simplest use-cases like ours.

We have achieved our two objectives Maintainability and Re-usability, only caveat would be that our number of components/screens remain the same.

If you think this solution is enough for now you can probably stop right here! But if you want to maybe reduce the number of screens and want just to be able to inject business logic into them dynamically then you can continue

How to make this layout reusable so that we can just inject business logic into it? More specifically how to dynamically get a business logic and inject it into our common layout.

Welcome to factory pattern using react hooks, by using this pattern we can solve all three problems that are

. Maintainability

. Re-usability

. Reduce number of screens

We can start by making a factory of hooks or in other words a Map of business logic with keys as their type. Where key can be the type we have in our apps.


type ScreenType = 'multi' | 'add' | 'sub'

type ScreenProps = {
  args: {a : number, b: number}
  type: ScreenType
}

// Result is the return type of all the hooks.
// Result type in this case will be forced upon all the react hooks 
// to make it type safe
const hooksFactory = { // Record<ScreenType, Result>
  multi: useMultiplication,
  add: useAddition,
  sub: useSubtraction
}
Enter fullscreen mode Exit fullscreen mode

This way of maintaining hooks is simple and powerful that we can literally use them anywhere in our app.

Now that we have our hooks map ready we can get any logic based on just the the type of the screen.

const useLogic = (props: ScreenProps) => 
  const hook = hooksFactory[props.type]
  return hook(props)
}
Enter fullscreen mode Exit fullscreen mode

This useLogic can be used in our common screen. We don’t have to make multiple screens now

// screen 1
const CommonScreen = (props: ScreenProps) => {
  const logic = useLogic(props)

  return <CommonLayout {...logic } />
};
Enter fullscreen mode Exit fullscreen mode

So we have managed to solve our problems of maintainability, re-usability and less number of screens.

You can experiment with the code here : React-Hook Factory

References:

Inspired from the technique used in this article https://dev.to/pietmichal/react-hooks-factories-48bi

Top comments (0)