Facory pattern with React Hooks
Tags: react, reactnative
Published: 2023-05-27 10:42:25

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

```ts
// 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>
  );
};
```

> 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.

```ts
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 } />
};

```

> 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.

```ts

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
}
```

> 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.

```ts
const useLogic = (props: ScreenProps) => 
  const hook = hooksFactory[props.type]
  return hook(props)
}
```

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

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

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

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](https://codesandbox.io/s/re-usable-efcu0o?file=/pages/screens/logic.tsx)

## **References:**

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