![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
dependency injection hooks for React.
Terso is a pragmatic hook and HOC library for React, that provides dependency injection to a React application. It uses inversify js as an IoC container, in combination with mobx for state management.
Is it a revolutionary library? No! It is just a collection of functions, born with the sole need of not wanting to copy/paste the same code into different projects.
Quick start in three easy steps
npm install terso
# yarn add terso
Add these entries in the compilerOptions
of your typescript config
"experimentalDecorators": true,
"types": ["reflect-metadata"],
interface TestModel extends ViewModel {
value: string;
}
const value = "the value";
@injectable()
class TestPresenter implements Presenter<TestModel> {
loadViewModel(): Promise<void> {
return Promise.resolve();
}
cleanModel(): Promise<void> {
return Promise.resolve();
}
get viewModel() {
return {
value: value,
};
}
}
function App() {
const model = useModel<TestModel>(TestPresenter);
return <div>{model.value}</div>;
}
function setup(container: Container) {
container
.bind<TestPresenter>(TestPresenter)
.to(TestPresenter)
.inSingletonScope();
}
const WithIoc = withIoc(App, setup);
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<WithIoc />);
App
in the terso
IoC Context// App.tsx
import { withIoc } from "terso";
import { Container } from "inversify";
import { configureContainer } from "./ioc/ioc.config";
function App() {
return <main>My app</main>
}
export default withIoc(App, configureContainer);
// ioc/ioc.types.ts
export const TYPES = {
TodoStore: Symbol.for("TodoStore"),
TodoBaseUrl: Symbol.for("TodoBaseUrl"),
};
// oic.config.js
import "reflect-metadata"
import {TYPES} from "./ioc.types";
//import {TodoStore } from "../stores/TodoStore"
//import {TodoStoreImpl } from "../stores/impl/TodoStoreImpl"
export function configureContainer(container: Container) {
// define here the dependencies of your code: services, api, repositories, configurattions
// for example:
container.bind<string>(TYPES.TodoBaseUrl).toConstantValue(/*config.todoBaseUrl*/ "some url");
// container
// .bind<TodoStore>(TYPES.TodoStore)
// .to(TodoStoreImpl)
// .inSingletonScope();
}
The function configureContainer
is mandatory and takes the IoC container as an argument. You can add (bind) alle the dependency you need in the app into the container.
import { useInject } from "terso";
import { observer } from "mobx-react-lite";
import { TYPES } from "../ioc/ioc.types";
import { TodoStore } from "../stores/TodoStore";
export default observer(function Todolist() {
const todoStore = useInject<TodoStore>(TYPES.TodoStore);
return (
<main>
<h2>Todo list</h2>
{todoStore.todos
.slice()
.map((todo) => (
<Todo key={todo.id} todo={todo} />
))}
</main>
);
})
terso
provides these hooks:
useInject
useModel
useInject
The hook useInject
takes an object from the IoC container and returns it, ready to be used in a React component.
Signature
useInject<T>(type: ServiceIdentifier<T>): T
Usage
const myService = useInject<MyServiceType>(MyServiceIdentifier);
Example
import { useInject } from "terso";
import { observer } from "mobx-react-lite";
import { TYPES } from "../ioc/ioc.types";
import { TodoStore } from "../stores/TodoStore";
export default observer(function Todolist() {
const todoStore = useInject<TodoStore>(TYPES.TodoStore);
return (
<main>
<h2>Todo list</h2>
{todoStore.todos
.slice()
.map((todo) => (
<Todo key={todo.id} todo={todo} />
))}
</main>
);
})
useModel
useModel
provides a ViewModel
implementation in a React Component.
A ViewModel
is an interface, borrowed from the famous pattern Model-View-Presenter. To use it you have to create an implementation of the ViewModel
interface and an implementation of a Presenter
that are defined as follows:
export interface ViewModel {
[key: string]: any;
}
export interface Presenter {
loadViewModel(): Promise<void>;
cleanModel(): Promise<void>;
viewModel: ViewModel;
}
The Presenter
interface provides a method to load the ViewModel
, a method to clean, and the ViewModel
itself.
Presenters are useful for leaving React components simple by giving them a flat object to display: the ViewModel
. The presenter hides the business logic from the React component, so finally React components can be used for what they were designed: creating user interfaces.
Signature
export function useModel<T extends ViewModel>(type: ServiceIdentifier<Presenter>): T
Usage
const viewModel = useModel<MyViewModelType>(MyPresenterIdentifier);
Example
// Todo.tsx
import { observer } from "mobx-react-lite";
import { Todo as TodoType } from "../../../domain/Todo";
import { useModel } from "terso";
import { TodoPresenter, TodoViewModel } from "../../../presenter/TodoPresenter";
interface TodoProps {
todo: TodoType;
}
export default observer(function Todo({ todo }: TodoProps) {
const viewModel = useModel<TodoViewModel>(TodoPresenter);
return (
<li className="todo-card">
<span className={todo.completed ? "done" : "todo"}>
{todo.id} - {todo.title}
</span>
{viewModel.canDelete && <button>delete</button>}
</li>
);
})
// TodoPresenter.ts
import { inject, injectable } from "inversify";
import { action, makeObservable, observable } from "mobx";
import { TYPES } from "../ioc/ioc.types";
import {
Permissions,
type AuthorizationService,
} from "../service/AuthorizationService";
import { type TodoStore } from "../service/TodoService";
import { Presenter, ViewModel } from "terso";
export interface TodoViewModel extends ViewModel {
canDelete: boolean;
}
@injectable()
export class TodoPresenter implements Presenter {
@inject(TYPES.TodoStore)
private readonly todoService!: TodoStore;
@inject(TYPES.AuthorizationServiceType)
private readonly authService!: AuthorizationService;
private canDelete: boolean = false;
constructor() {
makeObservable<TodoPresenter, "canDelete">(this, {
canDelete: observable,
loadViewModel: action,
});
}
loadViewModel(): Promise<void> {
this.canDelete = this.authService.hasPermission(Permissions.todo.delete);
return Promise.resolve();
}
cleanModel(): Promise<void> {
return Promise.resolve();
}
get viewModel(): TodoViewModel {
return {
canDelete: this.canDelete,
};
}
}
FAQs
Dependency injection hooks for React
We found that terso demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.