This is a tool to help you use the Singleton pattern within the React environment. Singleton classes can be used but will not be reactive when any instance attribute is changed. Reactive Singleton comes to solve this problem providing support to Typescript and Javascript projects.
To install the stable version:
Npm:
npm i reactive-singleton
Yarn:
yarn add reactive-singleton
createSingleton
const { watch, setClass } = createSingleton()
class MySingleton {
private static instance: MySingleton
public static getInstance(): MySingleton {
if (!MySingleton.instance) {
MySingleton.instance = new MySingleton()
}
return MySingleton.instance
}
public name = 'old name'
public updateData() {
/* when data needs to be changed */
watch((done) => {
this.name = 'new name'
done() // Notifies the Singleton Provider
})
}
}
/* some singleton class */
setClass(MySingleton)
Used to make the Singleton Pattern be listened to by React. You can implement the Singleton class as usual. After implementing the class, you have to use the first important API resource, it is createSingleton
. After calling the createSingleton()
method, it'll return the necessary methods to make your service (singleton) works within React:
watch
: Must be used when data needs to be updated inside the singleton class and watched by React;setClass
: Receives the singleton class as parameter. E.g:setClass(MySingletonClass)
.
useSingletonStatus
const status = useSingletonStatus(MySingleton) // "ready" or "in_progress"
This hook will let the app know the current status of a specific singleton's process. Returns "in_progress" when singleton's values are being changed and "ready" when it has been updated.
E.g:
const MyApp = () => {
// Will return "ready" before useEffect block
// Will return "in_progress" after useEffect block
// Will return "ready" after the data be updated inside the singleton instance
const status = useSingletonStatus(MySingleton)
const singletonData = MySingleton.getInstance()
useEffect(() => {
singletonData.updateData()
}, [])
return (/* component elements */)
}
useWasDataUpdated
const wasDataUpdated = useWasDataUpdated(MySingleton) // true or false
// You can optionally define the verification interval (debounce). Default is 500ms
const wasDataUpdated = useWasDataUpdated(MySingleton, 1000) // true or false
Lets the app know if the singleton data was updated. Returns true
or false
(boolean).
E.g:
const MyApp = () => {
// Returns 'false' before useEffect block
// Returns 'true' after useEffect block
const wasDataUpdated = useWasDataUpdated(MySingleton)
const singletonData = MySingleton.getInstance()
useEffect(() => {
singletonData.updateData()
}, [])
return (/* component elements */)
}
useReRenderOnUpdate
useReRenderOnUpdate(MySingleton) // Makes the component re-render every time the Singleton props are updated
The Singleton props can be modified in any level of the app and this hook makes the component re-render every time the props of the Singleton Class are updated. Useful for cases where a component is only reading the Singleton props. The props read by the component will always have the most updated data provided by the Singleton.
E.g:
const MyApp = () => {
useReRenderOnUpdate(MySingleton)
const { a, b } = MySingleton.getInstance()
console.log(a, b) // Will always have the most updated data
return (/* component elements */)
}
Note: You don't need to use this hook if you're using one of the following resources: withSingleton
or useSingletonStatus
.
withSingleton
The withSingleton
HOC works the same way as useReRenderOnUpdate
Hook. Every time that the Singleton props are changed, the component will re-render using the most updated data provided by the Singleton.
E.g:
const MyComponent = () => {
const { a, b } = MySingleton.getInstance()
console.log(a, b) // Will always have the most updated data
return (/* component elements */)
}
export default withSingleton(MyComponent, MySingleton)
Note: You don't need to use this HOC if you're using one of the following resources: useReRenderOnUpdate
or useSingletonStatus
.
That's basically this. Feel free to check out the live demos for a better understanding.
-
Using Typescript: TypeScript Example - CodeSandBox
-
Using Javascript (ES6): JavaScript Example - CodeSandBox
The only limitation here is, SINGLETON`S METHODS CAN NOT BE DESTRUCTURED. So, use them like:
const singletonData = MySingleton.getInstance()
// (!) Methods can't be destructured
singletonData.updateData()
}
- A few modules were updated.
- Updated important dependencies modules to improve security.
- SingletonProvider removed. This is no longer necessary due to changes in performance.
- Fixed the error message that was using an old resource reference
- Fixed the issue that was causing this error: React Hook "useWatcher" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function.
- The main API resources provided by
createSingleton()
was using a resouce calleduseWatcher
to be used inside the Singleton Classes, however this went against React Hooks rules.useWatcher
was renamed towatch
and thesetValue
was renamed tosetClass
. So that, the usage ofcreateSingleton()
should be used like:
const { watch, setClass } = createSingleton()
- Fixed the issue that caused components to re-render more than necessary when using hooks
- Added new hook:
useReRenderOnUpdate
- Added new HOC:
withSingleton
- New tests
- Fixed issue caused by multiple react-dom for ES6
- Peer dependencies changed
- Debounce added to useWasDataUpdated hook
- Tests
- CI
- Readme doc improved
- Order of rendering fixed
- Final bundle size was reduced
- Added JSDoc annotations
- Minified bundle
- Merged declarations
- First release;
MIT