striker-store
v2.0.3
Published
Simple abstraction for model managment in react apps with mobx
Downloads
22
Maintainers
Readme
striker-store
Like ember-data but for mobx and react
Table of Contents
Install
tl;dr
yarn add mobx mobx-react mobx-utils serializr striker-store
Why all those libraries ?
striker-strore is build on mobx stack, and our peer dependencies are mobx mobx-react mobx-utils serializr
.
Usage
This is a library that adds somethig like emaber-data
but for your React projects.
It also have an react-router
v4 integration to avoid boilerplate code.
Please check out demo
folder in source code. There is always up-to-date examples how to use library.
Models
Model is your domain data storage.
Your model is a class
that have at least one @identifier
decorator. This is value will be used to track your model id.
We provide an helper base class for model called DomainModel
. It will add a lot of lifecycle indication to your model. (isReloading, isError, isSaving, isSaved, isUpdating, isDeleting)
All this indicators are boxed values
. To learn more: https://mobx.js.org/refguide/boxed.html
You can also define @serializable
decorator to properties you want to serialize and deserialize.
You can also define you custom methods, for some computed values for example.
All serialization & deserialization process covered by serializr
library from @mwestrate
More info: https://github.com/mobxjs/serializr
Example
import { DomainModel } from 'striker-store'
import { serializable, identifier } from 'serializr';
class ExampleUserModel extends DomainModel {
@serializable(identifier()) id;
@serializable name;
}
Now you have all helpers you your model. And field id
will be used to track your model id.
Services
Service is communication with API.
Your service is a class
that implements next methods:
- fetchAll
- fetchOne
- createItem
- updateItem
- deleteItem
We do not restrict that under the hood what type of transport you are use. All you need is to return an Promise
from those methods.
Example
class ExampleUserService {
fetchAll() {
return fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json());
}
fetchOne(id) {
return fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then(response => response.json());
}
}
Store
You are here because of the store
. Store
use your service
to fetch/update/delete/create you data. Than use you model
to serialize/deserialize you data and store it in memory.
Manipulate methods
Store have following methods to manipulate with your data:
- fetchAll
- fetchOne
- createItem
- updateItem
- deleteItem
As you can see naming of the methods is equavilent of your service
methods.
Store Lifecycle
To add more control we provide hooks for you to override all aspects of store life.
Resolvers
It have next lifecycle (resolver) methods:
- storeDidFetchAll
- storeDidFetchOne
- storeDidCreateNew
- storeDidUpdate
- storeDidDelete
Those methods are used to map your backend response to what we need to save in store. Also, it can be used to show user notifications, etc.
By default all resolvers methods are next: (data) => data
But you can override it to what you need.
Also, this methods are async
. So you can resolve other data.
For example in Post
store when you fetch post by id, you need to fetch comments.
So you can get your comments store (with resolveStore
or by second arg in resolved method) and fetch the comments to specific post.
Hooks
In addition to those lifecycle methods there is will
lifecycle quavilents.
- storeWillFetchAll
- storeWillFetchOne
- storeWillCreateNew
- storeWillUpdate
- storeWillDelete
This is pretty similar of ES6 api of React component.
Also, we have fail
lifecycle hooks:
- storeFetchAllFailed
- storeFetchOneFailed
- storeCreateNewFailed
- storeUpdateFailed
- storeDeleteFailed
It is useful to track errors and show notifications or manipulate models in some cases.
Getters
And there is a methods to get your data from store:
- has
- getMap
- getOne
- asArray (getter/computed)
Store name and store resolving
All stores by default registered with name same as your class name.
So class: class MyStore {}
will be resitered as MyStore
.
To get stores from another stores (as was described in resolvers
serction) you should use stores
from resolvers did
hooks.
Example
Quick example using typescript:
import { serializable, identifier } from 'serializr';
import { BaseDomainStore } from 'striker-store';
import * as React from 'react';
import { observer } from 'mobx-react';
class ExampleUserModel {
@serializable(identifier()) id;
@serializable name;
}
class ExampleUserService {
fetchAll() {
return fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json());
}
fetchOne(id) {
return fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then(response => response.json());
}
}
class ExampleUserStore extends BaseDomainStore {
static service = new ExampleUserService();
static modelSchema = ExampleUserModel;
}
const store = new ExampleUserStore();
function doFetch() {
store.fetchAll();
}
function QuickExample() {
return (
<div>
<h2>Fetching</h2>
<div>Do initial fetch pls</div>
<div>
{store.asArray.map(user => <div key={user.id}> {user.name} </div>)}
</div>
<button onClick={doFetch}>Fetch</button>
</div>
);
}
export default observer(QuickExample);
ReactRouter v4 integration
There is an helper components to use react-router
.
Example
Please, check out crud-example
in demo
folder.
Examples
Please, check out demo
folder or https://stiker-store.surge.sh
Contribute
We are welcome to contribute. Just raise a pull request.