Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
coderoad-redux-js
Advanced tools
A CodeRoad tutorial for learning Redux.
CodeRoad is an open-sourced interactive tutorial platform for the Atom Editor. Learn more at CodeRoad.io.
install the tutorial package
npm install --save coderoad-redux-js
install and run the atom-coderoad plugin
Welcome! In this tutorial series we'll be exploring Redux, a tool for predictably managing state in your app.
We will be making a "Worst Pokemon" voting app. For the app, we'll need to setup some build tools.
Running > npm run setup
will do the following:
You'll find this "setup" script located in your package.json.
We'll be installing several NPM packages from terminal. You may consider installing a plugin for adding a terminal inside your editor, such as "platformio-ide-terminal".
In Redux, the store is the boss. Think of the store as holding the "single source of truth" of your application data.
Once created, the store has several helpful methods:
getState
to read the current data of your app.dispatch
to trigger actions. We'll look at actions more later.subscribe
to listen for state changesLet's get started by settings up the store for your Redux app. We will be working in "src/index.js".
An action is a named event that can trigger a change in your application data.
Actions are often broken into three parts to make your code more readable.
An action includes a named "type".
const action = { type: 'ACTION_NAME' };
Actions may also include other possible params needed to transform that data.
const getItem = { type: 'GET_ITEM', clientId: 42, payload: { id: 12 } };
Normal params passed in are often put inside of a payload
object. This is part of a standard called Flux Standard Action. Other common fields include error
& meta
.
An action creator is a functions that creates an action.
const actionName = () => ({ type: 'ACTION_NAME' });
Action creators make it easy to pass params into an action.
const getItem = (clientId, id) => ({ type: 'GET_ITEM', clientId: 42, payload: { id: 12 } });
Often, the action name is also extracted as an action type. This is helpful for readability and to catch action name typos. Additionally, most editors will auto-complete your action types from the variable name.
const ACTION_NAME = 'ACTION_NAME';
const GET_ITEM = 'GET_ITEM';
const action = () => ({ type: ACTION_NAME });
const getItem = (id) => ({ type: GET_ITEM, payload: { id }});
Let's write an action for voting up your choice of worst pokemon.
A reducer is what handles the actual data transformation triggered by an action.
In it's simplest form, a reducer is just a function with the current state and current action passed in.
const reducer = (state, action) => {
console.log(state);
return state;
};
We can handle different actions by matching on the action type. If no matches are found, we just return the original state.
const ACTION_NAME = 'ACTION_NAME';
const reducer = (state, action) => {
switch(action.type) {
// match on action.type === ACTION_NAME
case ACTION_NAME:
state = 42;
// return new state after transformation
return state;
default:
return state;
}
};
Our reducer is passed in as the first param when we create our store.
Redux totes itself as a "predictable" state container. This predictability is the product of some helpful restrictions that force us to write better code.
One such guideline: reducers must be pure functions.
When an action passes through a reducer, it should not "mutate" the data, but rather return a new state altogether.
case ADD_TO_ARRAY:
/* bad */
state.push(42); // push mutates the state
return state;
If multiple actions were pushing into the state, the functions are no longer pure and thus no longer fully predictable.
By returning an entirely new array, we can be sure that our state will be pure and thus predictable.
case ADD_TO_ARRAY:
/* good */
return state.concat(42); // returns a new array, with 42 on the end
Let's give writing pure reducers a try as we implement our VOTE_UP
action.
In Redux, we are not limited to writing a long, single reducer. Using combineReducers
allows us to create modular, composable reducers.
As our state is an object, for example:
{
pokemon: [ ... ],
users: [ ... ]
}
We can create a reducer to handle data transformations for each key in our state.
{
pokemon: pokemonReducer,
users: usersReducer
}
As our app grows, we can now think of the data in smaller chunks.
Let's try refactoring our app to use combineReducers
.
Our "index.js" file is getting a little long. Of course, our app will be more maintainable if we can divide it across different, well structured files.
There are different ways of structuring your app:
For simplicity in this example, we'll try putting our files together by function.
We still haven't worked with one of the most powerful features of Redux: middleware.
Middleware is triggered on each action.
1. Dispatch(action)
-> 2. Middleware(state, action)
-> 3. Reducer(state, action)
-> 4. state
Middleware is created with the store
. In it's most basic form, middleware can look like the function below:
const store => next => action => {
// do something magical here
return next(action);
// returns result of reducer called with action
}
Let's try out the power of middleware with "redux-logger".
Notice how the votes remain out of order. Let's create a sorting action for putting the highest votes at the top.
For this, we'll use a sorting function. A sorting function takes two values, and returns either:
1
: move ahead-1
: move behind0
: no changeSee an example for sorting votes below:
function sortByVotes(a, b) {
switch(true) {
case a.votes < b.votes: return 1;
case a.votes > b.votes: return -1;
default: return 0;
}
}
Let's setup a SORT_BY_POPULARITY
action to be called after each vote.
As we've seen in the previous steps, thunks sound more complicated than they really are. A thunk is just a function that returns a function.
Inside of middleware, we can determine if an action is returning a function.
const store => next => action => {
if (typeof action === 'function') {
// it's a thunk!
}
return next(action);
}
If it is a thunk, we can pass in two helpful params:
store.dispatch
store.getState
As we'll see, dispatch
alone can allow us to create async or multiple actions.
FAQs
Coderoad tutorial for using redux with raw javascript
The npm package coderoad-redux-js receives a total of 3 weekly downloads. As such, coderoad-redux-js popularity was classified as not popular.
We found that coderoad-redux-js demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.