Get started
Installation
- yarn
- npm
yarn add @azot-dev/x-core @legendapp/state
npm i @azot-dev/x-core @legendapp/state
File tree structure example
You can use any file tree structure you want, however I give one to get started
├── core
│ ├── dependencies
│ ├── services
│ │ ├── _services.ts
│ │ └── user.service.ts
│ ├── store
│ │ ├── _store.ts
│ │ └── user.store.ts
│ ├── utils
│ │ ├── service.ts
│ │ ├── hooks.ts
│ │ └── types.ts
│ ├── _core.ts
└── react
└── App.tsx
I use the underscore _ in some file names to keep them on top of their folder
Setup
The Store
// core/store/user.store.ts
type UserStore = {
firstName: string | null
lastName: string | null
}
export const userStore: UserStore = {
firstName: null,
lastName: null,
}
// core/store/_store.ts
export const store = {
user: UserStore,
};
The Services
// core/services/user-service.ts
import { Service } from '../utils/service';
export class UserService extends Service {
changeName(firstName: string, lastName: string) {
this.store.user.firstName.set(firstName);
this.store.user.lastName.set(firstName);
}
}
// core/_services.ts
import { UserService } from './user.service';
export const services = {
user: UserService,
};
Types
// core/utils/types.ts
import { services } from '../services/_services';
import { store } from '../store/_store';
export type StoreType = typeof store;
export type Dependencies = {}
export type Services = typeof services;
The Service class
As you can see, the Service class does not exist yet, it is the most important brick of the app in order to get strong typing and get it to work It is the only "magic" piece of code to copy paste, Unfortunately I could not create a factory for this because of circular dependencies, so if anyone can figure out how to move that piece of code in the library, PR welcome :)
// core/utils/service.ts
import { Observable } from '@legendapp/state';
import { BaseService } from '@azot-dev/x-core';
import { Dependencies, Services, StoreType } from './types';
export abstract class Service extends BaseService<
Services,
Observable<StoreType>,
DependenciesType
> {
constructor(
store: Observable<StoreType>,
dependencies: Partial<Dependencies>,
serviceRegistry: any
) {
super(store, dependencies, serviceRegistry);
}
}
The core
// core/_core.ts
import { createCoreFactory } from '@azot-dev/x-core';
import { services } from './services/_services';
import { store } from './store/_store';
import { Dependencies } from './utils/types';
export const Core = createCoreFactory<Dependencies>()(store, services);
The hooks
// core/utils/hooks.ts
import {
createSelectorHook,
createServiceHook,
} from '@azot-dev/x-core';
import { Core } from '../_core';
import { Store, Services } from './utils/types';
export const useAppSelector = createSelectorHook<Store>();
export const useAppService = createServiceHook<Services>();
React
// react/App.tsx
import React from 'react';
import {
XCoreProvider,
} from '@azot-dev/x-core';
import { Core } from '.';
const App = () => {
const userService = useAppService('user');
const user = useAppSelector((state) => state.user);
return (
<div>
<div>fist name: {user.firstName}</div>
<div>last name: {user.lastName}</div>
<button onClick={() => userService.changeName('John', 'Doe')}>change name</button>
</div>
);
};
const AppWrapper = () => {
return (
<XCoreProvider coreInstance={new Core()}>
<App />
</XCoreProvider>
);
};