init(config)
The function called to setup Rematch. Returns store
.
import { init } from '@rematch/core'
const store = init()
Init may also be called with the following configuration option below.
init({ models: { [string]: model } })
import { init } from '@rematch/core'
const count = {
state: 0,
}
init({
models: {
count,
},
})
For smaller projects, its recommend you keep your models in a "models.js" file and named export them.
export const count = {
state: 0,
}
For larger projects, its recommended you keep your models in a "models" folder and export them.
// models/count.js
export default {
state: 0,
}
// models/index.js
export { default as count } from './count'
export { default as settings } from './settings'
These can then be imported using * as alias
syntax.
import { init } from '@rematch/core'
import * as models from './models'
init({ models })
state: any
Required
The initial state of the model.
const example = {
state: { loading: false },
}
reducers: { [string]: (state, payload) => any }
An object of functions that change the model's state. These functions take the model's previous state and a payload, and return the model's next state. These should be pure functions relying only on the state and payload args to compute the next state. For code that relies on the "outside world" (impure functions like api calls, etc.), use effects.
{
reducers: {
add: (state, payload) => state + payload,
}
}
Reducers may also listen to actions from other models by listing the 'model name' + 'action name' as the key.
{
reducers: {
'otherModel/actionName': (state, payload) => state + payload,
}
}
effects: { [string]: (payload, rootState) }
An object of functions that can handle the world outside of the model.
{
effects: {
logState(payload, rootState) {
console.log(rootState)
}
}
}
Effects provide a simple way of handling async actions when used with async/await
.
{
effects: {
async loadData(payload, rootState) {
// wait for data to load
const response = await fetch('http://example.com/data')
const data = await response.json()
// pass the result to a local reducer
this.update(data)
}
},
reducers: {
update(prev, data) {
return {...prev, ...data}
}
}
}
effects
may also be declared as a factory. This way provides the ability to dispatch external model actions.
{
effects: dispatch => ({
async loadData(payload, rootState) {
// wait for data to load
const response = await fetch('http://example.com/data')
const data = await response.json()
// pass the result to a external model reducer
dispatch.other.update(data)
},
})
}
effects
that share a name with a reducer are called after their reducer counterpart
{
effects: {
// this will run after "update" reducer finished
update(payload, rootState) {
console.log('update reducer was called with payload: ', payload);
}
},
reducers: {
update(prev, data) {
return {...prev, ...data}
}
}
}
baseReducer: (state, action) => state
A reducer that will run before the model's reducers
. This function takes the model's previous state and an action, and returns the model state that reducers
will use.
This is especially useful for adding redux libraries to your store in a structured manner. See the recipe for redux plugins
init({
plugins: [loadingPlugin, persistPlugin],
})
Plugins are custom sets of init configurations or internal hooks that can add features to your Rematch setup.
Read more about existing plugins or about how to create your own plugins using the plugins API.
init({
redux: {
middlewares: [reduxLogger],
reducers: {
someReducer: (state, action) => ...,
}
},
})
There are situations where you might want to access Redux directly. You may want to:
- migrate an existing Redux project
- add middleware
- create a custom plugin
For a complete summary of all redux options, see the init Redux API.
As in Redux, a function that dispatches an action.
In Rematch, store.dispatch
can be called directly or as an object.
import store from './index'
const { dispatch } = store
// state = { count: 0 }
// reducers
dispatch({ type: 'count/increment', payload: 1 }) // state = { count: 1 }
dispatch.count.increment(1) // state = { count: 2 }
// effects
dispatch({ type: 'count/incrementAsync', payload: 1 }) // state = { count: 3 } after delay
dispatch.count.incrementAsync(1) // state = { count: 4 } after delay
Dispatch has an optional second property, "meta", which can be used in subscriptions or middleware. This is for advanced use cases only.
dispatch.count.increment(2, { syncWithServer: true })
As in Redux, returns the state of a store.
Provide a name for your store.
Use this when using multiple stores. The name will become the key when global getState
is called.
It's possible to lazy-load models and merge them into Rematch after init
has been called. Use store.model
.
import { init } from '@rematch/core'
const store = init({
models: {
count: { state: 0 },
},
})
store.getState()
// { count: 0 }
// later on
store.model({ name: 'countB', state: 99 })
store.getState()
// { count: 0, countB: 99 }
{ type: 'modelName/actionName', payload: any }
Actions are messages sent within Redux as a way for disparate parts of your app to communicate state updates.
In Rematch, an action is always structured with a type of "modelName" and "actionName" - referring to either a reducer or effect name.
Any data attached to an action is added in the payload.