-
Notifications
You must be signed in to change notification settings - Fork 293
Actions
Actions are plain objects dispatched by the application (usually from containers
) that describe changes on the store. Reducers
and sagas
listen to it so they can perform state changes and side effects, respectively, within the store.
A simple action looks like:
{
type: 'RESOURCE_UPDATE',
payload: {
needle: 1,
data: {
title: 'Hi!',
},
},
}
ARc uses action type constants and action creator methods to create those action objects following the Flux Standard Action pattern (FSA):
// src/store/resource/actions.js
export const RESOURCE_UPDATE = 'RESOURCE_UPDATE'
export const resourceUpdate = (needle, data) => ({
type: RESOURCE_UPDATE,
payload: {
needle,
data,
},
})
That way, other parts of the app, usually containers, can dispatch that action:
// src/containers/ResourceList.js
import { resourceUpdate } from 'store/actions'
store.dispatch(resourceUpdate(1, { title: 'Hi!' }))
Actions are the way for containers
to do things on the store. Ideally, when writing containers, the only things you will need to know is the action creator signature (resourceUpdate(needle, data)
) and how to access the state through selectors
(fromResource.getList(state)
). What happens in the middle (sagas
, reducers
, API calls
etc.) doesn't matter.
Consider the following action creator:
// bad
const resourceUpdate = payload => ({
type: RESOURCE_UPDATE,
payload,
})
The problem with that is that when dispatching resourceUpdate
from containers you don't know what you need to pass to payload
. You will need to read sagas and/or reducers to figure it out. It's a good practice to provide the API on the action creator signature:
// good
const resourceUpdate = (needle, data) => ({
type: RESOURCE_UPDATE,
payload: {
needle,
data,
},
})
ARc uses redux-saga-thunk so we can get promises when dispatching "pseudo-asynchronous" actions handled by sagas. It's necessary for cases when we need to wait for an action to complete its side effects before doing something:
store.dispatch(resourceUpdateRequest(1, { title: 'Hi!' })).then(...).catch(...)
For instance, we are using this on the PostForm
container (see the code).
See instructions on redux-saga-thunk to know how to do that.
Actions and action creators don't perform any change by themselves. Therefore, it doesn't make sense to name them imperatively like updateResource
. If it was the case, it would be more descriptive to name it like createResourceUpdateAction
.
That said, to make things simpler, but stay descriptive, ARc follows these naming conventions:
- Action types should be named as
MODULE_ACTION
. e.g.RESOURCE_UPDATE
,RESOURCE_UPDATE_REQUEST
; - Action creators should have the same name as their action type, but camelCased. e.g.
resourceUpdate
,resourceUpdateRequest
.
This way, we can read it like "store dispatches a resource update request on resource 1 changing its title to 'Hi'"!
store.dispatch(resourceUpdateRequest(1, { title: 'Hi!' }))
As pure functions, action creators are very easy to unit test:
test('resourceUpdateRequest', () => {
expect(resourceUpdateRequest(1, { title: 'Hi!' })).toEqual({
type: 'RESOURCE_UPDATE_REQUEST',
payload: {
needle: 1,
data: {
title: 'Hi!',
},
},
})
})
Special thanks to @kybarg and @protoEvangelion for helping to write this Wiki. Please, feel free to edit/create pages if you think it might be useful (also, see #33)