react-ts-super
v1.0.3
Published
Reactive state management framework for scalable react applications.
Downloads
2
Maintainers
Readme
Super is a state management framework for react that aims to simplify and streamline the development of reactive and scalable applications.
Features
- Reactive state management.
- Simple dependency injection.
Table of Contents
- Features
- Table of Contents
- Getting Started
- Usage
- Super Framework APIs
- Rx Types
- Dependency Injection
- Maintainers
- Credits
Getting Started
Add Super to your project:
npm i react-ts-super
Import the Super package into your project:
import { rxState, rxWatch } from 'react-ts-super';
import { Rx, Super, RxNotifier, SuperModel, SuperController, } from 'react-ts-super';
Usage
Counter App Example
The index.txs
file serves as the entry point for the application. It sets up the necessary framework for the project by wrapping the App component with SuperApp
, which enables the Super
framework.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { SuperApp } from 'react-ts-super';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<SuperApp>
<App />
</SuperApp>
</React.StrictMode>
);
reportWebVitals();
The SuperApp component is responsible for activating and deactivating the Super framework. It should be placed at the root of your application to enable the Super framework and configure its behavior.
Basic Counter
The App
component represents the root component of the counter application. It uses the Super framework to manage the state of the counter.
import React from 'react';
import './App.css';
import { useState, rxState } from 'react-ts-super';
const count = rxState(0);
function App() {
const state = useState(count);
function handleClick() {
count.state++;
}
return (
<div className="App">
<header className="App-header">
<button onClick={handleClick}>
Clicked {state} times
</button>
</header>
</div>
);
}
export default App;
In the basic counter implementation, we define a count variable using the rxState function from the Super framework. This function creates an Rx object that represents the reactive state of the counter.
The App component uses the useState function from the Super framework to synchronize the state of the count object with the component's local state. This allows the component to reactively update its UI whenever the counter state changes.
The handleClick function increments the count state by modifying the count.state property. The UI updates automatically to reflect the updated state.
Better Counter
The better counter implementation showcases the usage of a controller class and the SuperX component.
import React from 'react';
import './App.css';
import { SuperX, rxState, rxWatch, useController, SuperController } from 'react-ts-super';
class AppController extends SuperController {
public count = rxState(0);
public increment(): void {
this.count.state++;
}
rxWatch(() => console.log(this.count.state));
}
const appController = new AppController();
function App() {
const c = useController(appController); // Super.init(appController);
return (
<div className="App">
<header className="App-header">
<SuperX>
{() => (
<button onClick={c.increment}>
Clicked {c.count.state} times
</button>
)}
</SuperX>
</header>
</div>
);
}
export default App;
In the better counter implementation, we define an AppController class that extends SuperController from the Super framework. This controller class manages the state and logic for the counter functionality.
The count variable is defined as an Rx object using the rxState function within the AppController class.
We create an instance of AppController named appController and use the useController hook from the Super framework to manage the lifecycle of the controller.
The handleClick function increments the count state by modifying the c.count.state property. The UI updates automatically to reflect the updated state.
We use the SuperX component to subscribe to the changes in the count state and render the button component. The SuperX component listens to the Rx objects used inside it and re-renders only its children and not the entire component whenever the state changes.
The rxWatch function is used to log the count state to the console whenever it changes.
By separating the logic into a controller class and the UI into the component, we achieve a clear separation of concerns. The controller class manages the state and logic, while the component handles the UI and renders based on the state provided by the controller.
The Super framework enables reactivity and simplifies the management of state in the counter application.
This counter example demonstrates the power and simplicity of the Super framework for managing state in React applications.
Super Framework APIs
SuperApp
To enable the Super framework, import SuperApp and wrap your root component with it:
Example usage:
import { SuperApp } from 'react-ts-super';
ReactDOM.render(
<SuperApp testMode={true} mocks={[new MockAppController]}>
<App />
</SuperApp>,
document.getElementById('root')
);
By wrapping your application with SuperApp, you enable the Super framework and configure its behavior. The testMode prop determines whether the SuperApp is running in test mode, the autoDispose prop determines whether resources are automatically disposed of, and the mocks prop allows you to provide mock objects for dependency injection.
When the SuperApp component is mounted, it activates the Super framework with the specified configuration. When it is unmounted, it deactivates the Super framework and cleans up any resources.
Note: It is important to place the SuperApp component at the root of your application to ensure the Super framework is enabled for all components in your application.
useState
The useState hook is a custom hook for synchronizing the state of an Rx object with a React component's local state.
Code
function useState<T extends Object>(rx: Rx<T>): T;
Example usage:
const state = useState(rx);
The useState hook is used to synchronize the state of an Rx object with a component's local state. Whenever the Rx object's state changes, the component's state is updated accordingly.
By using the useState hook, you can easily integrate reactive state management into your React components, ensuring that the UI stays in sync with the underlying Rx object's state.
SuperDiv
The SuperDiv component is a React component that subscribes to an Rx object representing the state and renders its children whenever the state changes.
Example:
import React from 'react';
import { rxState, SuperDiv } from 'react-ts-super';
function App() {
const count = rxState(0);
return (
<SuperDiv rx={count}>
{(state) => <div>Count: {state}</div>}
</SuperDiv>
);
}
export default App;
In the example above, we create an Rx state named count
with an initial value of 0. We pass this Rx object to the SuperDiv component as the rx prop.
The children
function in the SuperDiv component receives the current state value as an argument (state)
and returns the rendered content. In this case, it renders a element with the text "Count: {state}".
Whenever the state of the count object changes, the SuperDiv component re-renders its children with the updated state value.
SuperX
The SuperX
component is a React component that subscribes to the Rx object(s) used inside it and renders its children whenever the state changes.
Example:
import React from 'react';\
import { rxState, SuperX } from './index';
function App() {
const count = rxState('SuperX')
return (
<div>
<SuperX>
{() => <div>Hello, {count.state}!</div>}
</SuperX>
</div>
);
}
export default App;
In the example above, we use the SuperX component to wrap the content we want to render. The children function ({() => <div>Hello, SuperX!</div>})
returns the desired content to be rendered.
Whenever the state of the Rx object(s) used inside the SuperX component changes, the component re-renders its children with the updated state.
Note: if you don't make use of an Rx object in the SuperX component, it will result in an error.
SuperController
A class that provides a lifecycle for controllers used in the application.
The SuperController
class allows you to define the lifecycle of your controller classes.
It provides methods that are called at specific points in the controller lifecycle, allowing you to initialize resources, handle events, and clean up resources when the controller is no longer needed.
Example usage:
class SampleController extends SuperController {
constructor() {
super();
}
const count = rxState(0);
const loading = rxState(false);
increment(): void {
this.count.state++;
}
toggleLoading(): void {
this.loading.state = !this.loading.state;
}
onDisable(): void {
this.count.dispose(); // Dispose Rx object.
this.loading.dispose();
super.onDisable();
}
}
In the example above, SampleController
extends SuperController
and defines a count
variable that is managed by an Rx
object. The increment()
method is used to increment the count state. The onDisable()
method is overridden to dispose of the Rx
object when the controller is disabled.
SuperModel
A class that provides value equality checking for classes.
Classes that extend this class should implement the props
getter, which returns a list of the class properties that should be used for equality checking.
Example usage:
class UserModel extends SuperModel {
constructor(id: number, name: string) {
super();
this.id = id;
this.name = name
}
const id: number;
const name: string;
get props(): Object[] {
return [this.id, this.name]; // Important
}
}
const user = rxState(UserModel(1, 'Paul'));
const user2 = UserModel(1, 'Paul');
user.state.equals(user2); // true
user.state = user2; // Will not trigger a rebuild
Rx Types
RxT
A reactive container for holding a state of type T
.
The RxT
class is a specialization of the Rx
class that represents a reactive state. It allows you to store and update a state of type T
and automatically notifies its listeners when the state changes.
Example usage:
const _counter = rxState(0);
function increment(): void {
_counter.state++;
}
// Listen to the state
rxWatch(() {
console.log(`Counter changed: ${_counter.state}`);
});
// Updating the state
_counter.increment(); // This will trigger the listener and print the updated state.
It is best used for local state i.e state used in a single controller.
Note: When using the RxT class, it is important to call the dispose()
method on the object when it is no longer needed to prevent memory leaks. This can be done using the onDisable method of your controller.
RxNotifier
An abstract base class for creating reactive notifiers that manage a state of type T
.
The RxNotifier
class provides a foundation for creating reactive notifiers that encapsulate a piece of immutable state and notify their listeners when the state changes. Subclasses of RxNotifier
must override the watch
method to provide the initial state and implement the logic for updating the state.
Example usage:
class CounterNotifier extends RxNotifier<number> {
watch(): number {
return 0; // Initial state
}
increment(): void {
state++; // Update the state
}
}
// Listen to the state
rxWatch(() {
print(`Counter changed: ${counterNotifier.state}`);
});
// Updating the state
counterNotifier.increment(); // This will trigger the listener and print the updated state.
It is best used for global state i.e state used in multiple controllers but it could also be used for a single controller to abstract a state and its events e.g if a state has a lot of events, rather than complicating the controller, an RxNotifier could be used for that singular state instead.
Note: When using the RxNotifier class, it is important to call the dispose()
method on the object when it is no longer needed to prevent memory leaks. This can be done using the onDisable method of your controller.
Dependency Injection
of
Retrieves the instance of a dependency from the manager and enables the controller if the dependency extends SuperController
.
Super.of<T>();
init
Initializes and retrieves the instance of a dependency, or creates a new instance if it doesn't exist.
Super.init<T>(T instance);
create
Creates a singleton instance of a dependency and registers it with the manager.
Super.create<T>(T instance);
delete
Deletes the instance of a dependency from the manager.
Super.delete<T>();
deleteAll
Deletes all instances of dependencies from the manager.
Super.deleteAll();
Maintainers
Credits
All credits to God Almighty who guided me through the project.