How to stop infinite loop without breaking React's rule of hooks (useEffect)

I have many different places where I have to use the same logic, so I have generalized my logic system into a class...

...
const contextLayer = new contextLayerCore(...useState([]));
...

This class provides me with a bunch of functions like addContext, removeAll, etc. However, the addContext function is a bit problematic...

...
addContext(context: listing) {
  this.setState([...this.state, context]);
}
...

Simple enough; all it does is append an object using the setState function which should re-render any components using the state. Here's the problem, this causes an infinite loop...

...
this.setState([...this.state, context]);
//                     ^
// also updates when state updates, hence re-runs the setState function
...

This causes and infinite loop. I could using useEffect(..., []) to make it not be dependant, however, this is a function inside a class, thus it breaks React's rules of hooks.

I have to retain the functionality of this class, so I cannot move the function up into the component(s) as a lot of components use this class and would simply create duplicate code.

And example of where it is used...

...
<ContextSuperContainer render={contextLayer.state} />
...

What should I do? Is there an alternative of useEffect? Should I be using a different system for this purpose?

Edit: Solution

Convert it to a custom hook!

export default function useContextLayer (initialState: Array<listing>) {
  const [state, setState] = useState(initialState);

  return {
    removeAll: () => {...},
    addContext: () => {...},
    // doesn't even need an useEffect anymore
  }
}

24