Looking at Redux.js for the first time can be overwhelming because there are so many moving parts. There are a few similar-sounding terms to learn such as actions, action types, and action creators. Understanding what they are and how to use them is the first step to adding Redux to your application.
Action Type
An action type is a string that simply describes the type of an action. They're commonly stored as constants or collected in enumerations to help reduce typos and because programmers love organization. I've found it helpful to structure my action types like this:
export const Actions = { GET_USER_DETAILS_REQUEST: 'GET_USER_DETAILS_REQUEST', GET_USER_DETAILS_SUCCESS: 'GET_USER_DETAILS_SUCCESS', GET_USER_DETAILS_FAILURE: 'GET_USER_DETAILS_FAILURE', UPDATE_USER_DETAILS_REQUEST: 'UPDATE_USER_DETAILS_REQUEST', UPDATE_USER_DETAILS_SUCCESS: 'UPDATE_USER_DETAILS_SUCCESS', UPDATE_USER_DETAILS_FAILURE: 'UPDATE_USER_DETAILS_FAILURE', // more...};
Action
An action is like a message that we send (i.e. dispatch) to our central Redux store. It can literally be anything. But ideally we want to stick to an agreed-upon pattern. And the standard pattern is as follows (this is a TypeScript type declaration):
type Action = { type: string; // Actions MUST have a type payload?: any; // Actions MAY have a payload meta?: any; // Actions MAY have meta information error?: boolean; // Actions MAY have an error field // when true, payload SHOULD contain an Error};
(The question marks mean the property is optional. So you only need the type property at a minimum).
An action to fetch the user named Dan might look something like this
{ type: 'GET_USER_DETAILS_REQUEST', payload: 'Dan'}
But you don't typically hardcode an action like this. You'd use an action creator.
Action Creator
As you might expect, an action creator is a function that creates and returns an action. Okay well... this is not always true. But for the purposes of learning Redux, you can pretend it's true for now.
Simple action creators look like this:
// in ES5 (also valid in ES6)export function getUserDetailsRequest(id) { return { type: Actions.GET_USER_DETAILS_REQUEST, payload: id, };}// in ES6export const getUserDetailsRequest = id => ({ type: Actions.GET_USER_DETAILS_REQUEST, payload: id,});
(Note: If you're concerned about too much 'boilerplate' then redux-actions will help you greatly reduce it).
When writing basic Redux, an action creator simply returns an action. You would typically dispatch the action to your store immediately.
store.dispatch(getUserDetailsRequest('Dan'));
Although, realistically, you'll be doing this via dispatch properties that are passed into a React component like this:
// ES5export function mapDispatchToProps(dispatch) { return { onClick: function() { dispatch(getUserDetailsRequest('Dan')); } };}// ES6export const mapDispatchToProps = dispatch => ({ onClick: () => dispatch(getUserDetailsRequest('Dan'))});
Later on, you'll have to deal with asynchronous actions such as making an AJAX call to the server. If you choose to use redux-thunk to manage your asynchronous code then you'll have complex action creators that dispatch multiple actions directly to the store rather than returning a single action for you to dispatch.
Personally, I prefer redux-saga over redux-thunk. With redux-saga, your action creators stay simple.
Further Reading
- Starting a React/Redux Project with TypeScript
- A Simple Naming Convention for Action Creators
- A Fun Introduction to Redux-Saga
- Flux Standard Actions