Categories
Redux

Creating Our Own Redux Middleware

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it also as a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to create our own Redux middleware.

Middleware

Middleware is some code that we can put between dispatching an action and the moment that the action reaches the reducer.

To do this in a clean way, we define a function that takes the store as a parameter, which returns a function that takes the next function, which is the same as the dispatch function, which then returns a function that takes an action parameter and returns next(action) .

We can do that as follows:

import { createStore, applyMiddleware } from "redux";

function countReducer(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const logger = store => next => action => {
  console.log("dispatching", action);
  let result = next(action);
  console.log("next state", store.getState());
  return result;
};

let store = createStore(countReducer, applyMiddleware(logger));
store.subscribe(() => store.getState());
store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });

In the code above, we have the logger middleware, which is a function that takes the store parameter which holds the Redux store itself, which then returns a function that takes the next function, which the same as store.dispatch . This function then returns a function that takes the action parameter, which is our action object which we called dispatch with.

In the function that takes action , first, we log action, then we call next with action , then we take the returned result and assigned it to result .

Then we log store.getState() , and return result .

To use the logger middleware we just defined, we write:

let store = createStore(countReducer, applyMiddleware(logger));

Then when we run dispatch we’ll see the console.log output from the logger.

Returning Non-Plain Objects with Middleware

We don’t have to return plain objects with middleware.

For example, we can also return a promise as follows:

const promiseMiddleware = store => next => action => {
  if (!(action instanceof Promise)) {
    return next(action);
  }
  return (async () => {
    const resolvedAction = await Promise.resolve(action);
    store.dispatch(resolvedAction);
  })();
};

In the code above, we returned a promise, which isn’t a plain object.

All it does is that if we pass in a promise into dispatch , it’ll resolve the promise and then call store.dispatch with the resolved action.

We can then call the applyMiddleware function when the createStore function is called.

Note that we called our async function, we don’t just return it. We have to call store.dispatch so that the values from our actions will be set in the store.

Defining and Using Multiple Middlewares

We can create and apply multiple middlewares when we call applyMiddleware . To do this, we just pass it all the middlewares for applyMiddleware .

For example, if we want to apply all the middlewares in the examples we have above, we can write:

import { createStore, applyMiddleware } from "redux";

function countReducer(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

const logger = store => next => action => {
  console.log("dispatching", action);
  let result = next(action);
  console.log("next state", store.getState());
  return result;
};

const promiseMiddleware = store => next => action => {
  if (!(action instanceof Promise)) {
    return next(action);
  }
  return (async () => {
    const resolvedAction = await Promise.resolve(action);
    store.dispatch(resolvedAction);
  })();
};

let store = createStore(
  countReducer,
  applyMiddleware(promiseMiddleware, logger)
);
store.subscribe(() => store.getState());
store.dispatch(Promise.resolve({ type: "INCREMENT" }));
store.dispatch({ type: "DECREMENT" });

Since we have our promiseMiddleware , we can now pass in promises to dispatch and set the value in the store.

Therefore, we can write:

store.dispatch(Promise.resolve({ type: "INCREMENT" }));
store.dispatch({ type: "DECREMENT" });

and we won’t get an error.

With the logger middleware, we get console.log output.

Conclusion

We can define middleware to do more than what we can do with Redux itself.

To do this, we define a function that takes the store as a parameter, which returns a function that takes the next function, which is the same as the dispatch function, which then returns a function that takes an action parameter and returns next(action) .

The function has to call dispatch so that the action object can be propagated to the reducer.

We can chain middlewares with the applyMiddleware function, which takes one or more middlewares.

Categories
Redux

Dispatching Async Actions with Redux

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to dispatch actions asynchronously.

Async Actions

In JavaScript, a lot of things have to be done asynchronously to avoid blocking the main execution thread.

Redux can dispatch asynchronous actions so that we don’t always have to change states synchronously.

To do this, we use the Redux-Thunk middleware. We can apply middlewares by using Redux’s applyMiddleware function.

With that, we can pass in functions that call dispatch instead of plain objects. We need this capability to run async actions that call dispatch and populate the store with it.

We can do this as follows:

import { createStore, applyMiddleware } from "redux";
import thunkMiddleware from "redux-thunk";

function jokeReducer(state = {}, action) {
  switch (action.type) {
    case "SET_JOKE":
      return action.joke;
    default:
      return state;
  }
}

let store = createStore(jokeReducer, applyMiddleware(thunkMiddleware));

function fetchJoke() {
  return async dispatch => {
    const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
    const joke = await response.json();
    dispatch({ type: "SET_JOKE", joke });
  };
}

(async () => {
  await store.dispatch(fetchJoke());
  console.log(store.getState().value.joke);
})();

In the code above, we have the jokeReducer which is the same as what we have before.

Then in to create the store, we write:

let store = createStore(jokeReducer, applyMiddleware(thunkMiddleware));

The difference from stores that only take plain object actions is that we have the applyMiddleware function where we passed in the thunkMiddleware.

The thunkMiddleware lets us pass in functions to dispatch instead of a plain object without it.

In the function we pass in, we can call dispatch with plain objects to do the synchronous actions.

Then we defined the fetchJoke function, which is or action creator, as follows:

function fetchJoke() {
  return async dispatch => {
    const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
    const joke = await response.json();
    dispatch({ type: "SET_JOKE", joke });
  };
}

In this function, we returned an async function that has the Redux dispatch function as the parameter.

Then once we get the joke with the Fetch API, we call dispatch provided in the parameter.

This way the Thunk middleware can call dispatch in the returned function.

We can return any function, but we need to use thunks for async functions since they don’t return plain objects.

Ordinary action creators must return plain objects, but if we use the Redux Thunk middleware, we can return a function that calls dispatch and getState.

Then we dispatch our async action and get the value from it as follows:

(async () => {
  await store.dispatch(fetchJoke());
  console.log(store.getState().value.joke);
})();

All we did above was call dispatch with the promise that the fetchJoke function returned as we defined above. Then we use store.getState().value.joke to get the joke’s value from the store.

Photo by Sincerely Media on Unsplash

Checking State Before Dispatching Synchronous Actions in Our Async Action Creator

We can write a function to check the state before getting data. To do this, we can make the following changes while keeping everything else the same:

function shouldFetchJoke(state) {
  return !state.value || !state.value.joke;
}

function fetchJoke() {
  return async (dispatch, getState) => {
    if (shouldFetchJoke(getState())) {
      const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
      const joke = await response.json();
      dispatch({ type: "SET_JOKE", joke });
    }
  };
}

In the code above, we defined the shouldFetchJoke function which checks the state.value and state.value.joke to see if the value has been set.

Then we change fetchJoke to call shouldFetchJoke . Then we take advantage of the getState parameter to get the state and check if a joke already exists in the store with shouldFetchJoke .

If not, then we proceed to get the joke.

Conclusion

With the Redux Thunk middleware, we can pass in actions that aren’t plain objects to dispatch.

To use it, we have to call applyMiddleware with the thunkMiddleware as the argument.

Then we can create an action creator that returns a function with the dispatch and getState functions as the first and second parameter respectively, then we can get the state with getState as usual.

Categories
Redux

Introduction to Redux Actions and Reducers

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to create actions that we can dispatch to our store with Redux.

Create a Store with a Single Reducer

We can create a store with a single reducer by creating a reducer function. Then we can use Redux’s createStore function to create the store from the reducer.

With the store, we get to subscribe to it to get the latest values, and also dispatch actions with it to update the state in the store by passing it to the reducer.

For example, we can write the following code to create the store and run some actions:

import { createStore } from "redux";

function todosReducer(state = [], action) {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, action.todo];
    case "REMOVE_TODO":
      return state.filter(todo => todo !== action.todo);
    default:
      return state;
  }
}

let store = createStore(todosReducer);

store.subscribe(() => console.log(store.getState()));

store.dispatch({ type: "ADD_TODO", todo: "eat" });
store.dispatch({ type: "ADD_TODO", todo: "drink" });
store.dispatch({ type: "REMOVE_TODO", todo: "eat" });

In the code above, we created the todosReducer to receive the dispatched actions and then manipulate the state as we wish to do.

We have the switch statement to check the action’s type and then act accordingly.

The action type is indicated in the object that we passed into the dispatch method.

If the action type is “ADD_TODO” , then we insert the todo item in object we have in dispatch ‘s argument to the end of the array, and we spread all the old values before it.

If the action type is “REMOVE_TODO” , then we return a new array that excludes the todo item with the given todo text.

Otherwise, we return what we already have.

Then we use the createStore method to create the store so we can call dispatch to pass in plain objects to manipulate the data in the store.

We can also subscribe to it and then call getState() to get the latest values.

Note that we always make a copy of state and then return something new with it. This prevents accidental changes from mutating objects unintentionally.

Create a Store with a Multiple Reducers

In most apps, we want to store more than one kind of data in our store. We can do that by creating multiple reducers and then use the combineReducer function from Redux to combine them into one store.

To do this we can write something like the following code:

import { createStore, combineReducers } from "redux";

function todosReducer(state = [], action) {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, action.todo];
    case "REMOVE_TODO":
      return state.filter(todo => todo !== action.todo);
    default:
      return state;
  }
}

function countReducer(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
}

let reducers = combineReducers({
  todos: todosReducer,
  count: countReducer
});
let store = createStore(reducers);

store.subscribe(() => console.log("todos", store.getState().todos));
store.subscribe(() => console.log("count", store.getState().count));

store.dispatch({ type: "ADD_TODO", todo: "eat" });
store.dispatch({ type: "ADD_TODO", todo: "drink" });
store.dispatch({ type: "REMOVE_TODO", todo: "eat" });

store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });

In the code above, we have 2 reducers — todoReducer and countReducer .

We combined them into one by calling Redux’s combineReducers function with the name of the state as the property name and the reducer function as the value.

combineReducers combines all the reducers into one reducer, so we can pass it into createStore . We can choose any state name we want.

The store is created by passing the big reducer returned from combineReducers .

Then in the subscribe callbacks, we can use store.getState() to get all the states. Then we can get the todos with the todos property and the count state with the count property.

In the console.log s, we should get something like:

todos ["eat"]
count 0
todos ["eat", "drink"]
count 0
todos ["drink"]
count 0
todos ["drink"]
count 1
todos ["drink"]
count 0

This is because we subscribed to the store and then get the state from each reducer individually.

The dispatch method is called as we did with the single reducer example.

We still pass in the action type and payload if there is one.

Since dispatch works the same as no matter how many reducers we have in the store, we should make sure that no 2 actions have the same name.

Photo by Roberto Nickson on Unsplash

Notes

combineReducers will throw errors in some cases to reduce the chance of committing bugs.

It’ll throw an error if a reducer function doesn’t return the state given to it as the first argument if the action isn’t recognized.

Also, it must never return undefined . It’s too easy to do this via an early return statement. Therefore, combineReducers will throw an error if we do that instead of letting the error manifest somewhere else.

If the state given to it is undefined , it must return the initial state for the specific reducer. This means that the initial state can’t be undefined .

We can specify the initial state as the default argument for the state parameter.

Redux will check for these rules when we’re writing our code.

Conclusion

We can create a store from one more reducer function. The only difference is that we have to use combineReducers to combine multiple reducers into one big reducer in order to pass it into createStore . We can pass in a single reducer straight into createStore .

Then we can use getState to get the latest returned state of all reducers. The states are available from getState() and we can get the properties from the returned object of getState to get those states.

Dispatching actions is the same regardless of how many reducers we have in our store.

Categories
Redux

Introduction to State Management with Redux

With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to create a basic store in the app and use it.

Installation

Redux is available as an NPM package. We can install it by running:

npm install --save redux

with NPM or:

yarn add redux

with Yarn.

Basic Example

We can use redux to store the state of an app by creating a store and reducer.

Then we can subscribe to the store to get the data and dispatch actions to make changes to the state.

For example, we can write:

import { createStore } from "redux";

function counter(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + action.payload || 1;
    case "DECREMENT":
      return state - action.payload || 1;
    default:
      return state;
  }
}

let store = createStore(counter);
store.subscribe(() => console.log(store.getState()));

store.dispatch({ type: "INCREMENT", payload: 2 });
store.dispatch({ type: "DECREMENT", payload: 1 });

In the code above, we have the counter reducer function which gets the action type and payload and then applies it accordingly.

The counter function checks for action type INCREMENT and DECREMENT and return the new state with the payload added to it.

Then we create the store by running:

let store = createStore(counter);

After that, we can subscribe to the store by calling subscribe on the store and then call getState within the callback for it as follows:

store.subscribe(() => console.log(store.getState()));

Then we can dispatch actions to the store by calling dispatch on it with an object with the type and payload , which will be passed into the counter function in the action parameter.

Therefore, the state will be updated by the action since for the first dispatch call:

store.dispatch({ type: "INCREMENT", payload: 2 });

The type will be passed in as action.type and payload will be set as action.payload to counter .

action.type is ‘INCREMENT’ and action.payload is 2.

Likewise, action.type is ‘DECREMENT’ and action.payload is 1 in the second call.

Note that we don’t mutate the state directly in counter . We return a new state by deriving it from the existing state.

Three Principles of Redux

Three principles apply to the way Redux is built.

Single Source of Truth

Redux stores state in a single place. This makes getting data easy since we only have to get it in one place.

Debugging is also easy because of that. This makes development faster.

Some functionality that was hard to implement now can be easy since now the state is stored in a single tree.

State is Read-Only

The state is read-only so it can’t be changed by accident. We have to express an intent to change the state.

There aren’t subtle race conditions to watch out for since all changes are centralized and happen one by one in strict order.

Since actions are just plain objects, they can be logged, serialized, stored and replayed for debugging and testing purposes.

Changes are Made With Pure Functions

Reducers are pure functions that take the previous state and action and return the next state. We return new state objects instead of mutation previous state.

We can start with a single reducer and then split it off into smaller reducers that management other parts of the state tree.

We can control how they’re called, pass additional data, or make reusable reducers.

Flux Architecture

Redux concentrates all model update logic in one layer of an app. This is one part of the Flux architecture that’s adopted by Redux.

Redux doesn’t have a dispatcher. It relies on pure functions instead of event emitters to change state.

Pure functions are easy to compose and doesn’t need extra management.

Redux assumes that we never mutate our data. We should always return new objects. This is easy now that we have the spread operator for objects.

Photo by Kelly Sikkema on Unsplash

RxJS

We can turn a Redux store into an Rxjs Observable by subscribing to it and calling nexr to return the latest state.

For example, we can write:

import { createStore } from "redux";

function counter(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + action.payload || 1;
    case "DECREMENT":
      return state - action.payload || 1;
    default:
      return state;
  }
}

let store = createStore(counter);

function toObservable(store) {
  return {
    subscribe({ next }) {
      const unsubscribe = store.subscribe(() => next(store.getState()));
      next(store.getState());
      return { unsubscribe };
    }
  };
}

const counterObservable = toObservable(store);

counterObservable.subscribe({
  next(count) {
    console.log(count);
  }
});

store.dispatch({ type: "INCREMENT", payload: 2 });
store.dispatch({ type: "DECREMENT", payload: 1 });

In the code above, we have:

function toObservable(store) {
  return {
    subscribe({ next }) {
      const unsubscribe = store.subscribe(() => next(store.getState()));
      next(store.getState());
      return { unsubscribe };
    }
  };
}

const counterObservable = toObservable(store);

counterObservable.subscribe({
  next(count) {
    console.log(count);
  }
});

store.dispatch({ type: "INCREMENT", payload: 2 });
store.dispatch({ type: "DECREMENT", payload: 1 });

The toObservable returns an Observable which we can subscribe to since it returns a subscribe method.

The Redux store’s subscribe method returns an unsubscribe function so we can unsubscribe to it when we no longer need it.

Then when we call dispatch above, we’ll get the new values logged in the next function above.

Conclusion

We can store an app’s data in a central place with Redux. To do this, we create a store and then subscribe to it to get the latest state from it.

Then we call dispatch on the store with a plain object with the action type and payload to change the store to the latest state.

Categories
React

Render Code Diffs in a React App with the React Diff Viewer Library

To make rendering code diffs easier in a React app, we can use the React Diff Viewer library.

In this article, we’ll look at how to render code diffs with the React Diff Viewer library.

Installation

We can install the package by running:

npm i react-diff-viewer

or:

yarn add react-diff-viewer

Rendering the Diffs

To render the diffs in our React app, we can use the ReactDiffViewer component.

For example, we can write:

import React from "react";
import ReactDiffViewer from "react-diff-viewer";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')

if(a > 10) {
  console.log('bar')
}

console.log('done')
`;
const newCode = `
const a = 10
const boo = 10

if(a === 10) {
  console.log('bar')
}
`;

export default function App() {
  return (
    <div className="App">
      <ReactDiffViewer oldValue={oldCode} newValue={newCode} splitView={true} />
    </div>
  );
}

We pass in the old code string into the oldValue prop and the new code into the newValue prop.

Also, we can hide the line numbers with the hideLineNumers prop.

splitView shows the old and new code side by side.

Compare Method

We can change the compare method of for diffing with the compareMethod prop:

import React from "react";
import ReactDiffViewer from "react-diff-viewer";
import Prism from "prismjs";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')

if(a > 10) {
  console.log('bar')
}

console.log('done')
`;
const newCode = `
const a = 10
const boo = 10

if(a === 10) {
  console.log('bar')
}
`;

export default function App() {
  return (
    <div className="App">
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        splitView={true}
        compareMethod="diffWords"
      />
    </div>
  );
}

Styling

We can change the styles by passing in the styles prop:

import React from "react";
import ReactDiffViewer from "react-diff-viewer";
import Prism from "prismjs";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')

if(a > 10) {
  console.log('bar')
}

console.log('done')
`;
const newCode = `
const a = 10
const boo = 10

if(a === 10) {
  console.log('bar')
}
`;

const newStyles = {
  variables: {
    dark: {
      highlightBackground: "#fefed5",
      highlightGutterBackground: "#ffcd3c"
    }
  },
  line: {
    padding: "10px 2px",
    "&:hover": {
      background: "purple"
    }
  }
};

export default function App() {
  return (
    <div className="App">
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        splitView={true}
        styles={newStyles}
      />
    </div>
  );
}

We set it to an object with specific properties to set the styles.

highlightBackground sets the background color for highlights.

highlightGutterBackground sets the color for the gutter.

line is the styles for each line.

We can change the hover style of a line with the &:hover property.

Conclusion

We can use the React Diff Viewer component to add a code diff view into our React app.