Last active
September 18, 2018 15:47
-
-
Save mujuni88/03c001a72685ba848ed3fd3a908f8b3d to your computer and use it in GitHub Desktop.
Store Template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Example of an entity/model class | |
*/ | |
import { | |
observable, | |
action | |
} from 'mobx' | |
import { setter } from 'mobx-decorators' | |
export class Entity { | |
id = null | |
parentStore = null | |
@setter | |
@observable | |
name = '' | |
constructor(parentStore, config) { | |
this.parentStore = parentStore // optional. | |
this.updateFromJson(config) | |
} | |
@action | |
updateFromJson({ id, name }) { | |
this.id = id | |
this.name = name | |
} | |
@action | |
delete = () => { | |
this.parentStore.delete(this) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* The Store is responsible for the following: | |
* 1. Holding the state of entities | |
* 2. Fetching entities | |
* 3. Creating entities | |
* 4. Deleting entities | |
* 5. Updating entities | |
* | |
* An Entity could be an object or a class. | |
* Prefer using Entity classes because you can do more with them. | |
*/ | |
import { observable, action, autorun, computed } from 'mobx' | |
import { setter } from 'mobx-decorators' | |
import xhr from 'helpers/XHR' | |
import uiStore from 'stores/UiStore' | |
import getError from 'helpers/ErrorParser' | |
import Entity from 'stores/models/Entity' | |
/* | |
* Example of a store | |
*/ | |
export class StoreTemplate { | |
@setter | |
@observable | |
isLoading = false | |
@setter | |
@observable | |
isError = false | |
@observable | |
entities = observable.map() // array could work to | |
contructor() { | |
this.initAutoruns() | |
} | |
// Computed | |
@computed | |
get hasErrors() { | |
return !this.isLoading && this.isError | |
} | |
// Actions | |
/* | |
* All autoruns are initialized in this function | |
*/ | |
@action | |
initAutoruns = () => { | |
this.autoErrorNotifier() | |
} | |
/* | |
* This autorun will be ran automatically whenever the [observable] property [isError] is changed. | |
* This will automatically show a notification message to the user | |
*/ | |
@action | |
autoErrorNotifier = () => { | |
this.autoErrorDisposer = autorun('Watch errors', () => { | |
if (this.isError && !this.isError.hideNotification) { | |
uiStore.addNotification({ | |
title: this.isError.title, | |
message: this.isError.message, | |
type: this.isError.type || 'error' | |
}) | |
} | |
}) | |
} | |
/* | |
* CRUD operations that the store is responsible for | |
*/ | |
@action | |
createEntity = json => { | |
this.entities.set(json.id, new Entity(this, json)) | |
} | |
@action | |
deleteEntity = entity => { | |
this.entities.delete(entity.id) | |
} | |
@action | |
updateEntity = json => { | |
const entity = this.entities.get(json.id) | |
entity && entity.update(json) | |
} | |
/* | |
* Example of a XHR get function. | |
* | |
* Important things: | |
* 1. Clear errors before fetching | |
* 2. Set loading before fetching | |
* 3. Catch errors in the catch block | |
* 4. Clear loading in the finally block | |
* 5. MOST IMPORTANT: After a response, all changes are placed inside an action function fetchExampleOK. | |
*/ | |
@action | |
fetchExample = async () => { | |
try { | |
this.setIsLoading(true) | |
this.setIsError(false) | |
const response = await xhr.get('/groups', { | |
params: { | |
type: 'user' | |
} | |
}) | |
this.fetchExampleOK(response) | |
} catch (e) { | |
this.setIsError(getError(e)) | |
} finally { | |
this.setIsLoading(false) | |
} | |
} | |
@action | |
fetchExampleOK = response => { | |
console.log(response.header) | |
console.log(response.data) | |
response.data.forEach(this.createEntity) | |
} | |
/* | |
* Example of a XHR post function. | |
* | |
* Important things: | |
* 1. Clear errors before fetching | |
* 2. Set loading before fetching | |
* 3. Catch errors in the catch block | |
* 4. Clear loading in the finally block | |
* 5. MOST IMPORTANT: After a response, all changes are placed inside an action function postExampleOK. | |
*/ | |
@action | |
postExample = async () => { | |
try { | |
this.setIsLoading(true) | |
this.setIsError(false) | |
const data = { id: 1, body: 'Hello world' } | |
const response = await xhr.post('/groups', data) | |
this.postExampleOK(response) | |
} catch (e) { | |
this.setIsError(getError(e)) | |
} finally { | |
this.setIsLoading(false) | |
} | |
} | |
@action | |
postExampleOK = response => { | |
console.log(response.header) | |
console.log(response.data) | |
response.data.forEach(this.updateEntity) | |
} | |
/* | |
* dispose all autoruns here to avoid subtle memory leak issues | |
*/ | |
@action | |
dispose = () => { | |
this.autoErrorNotifier && this.autoErrorNotifier() | |
} | |
} | |
export default new StoreTemplate() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment