Tips to learn React + Redux in 2018

I am implemeting applications in React and Redux for quite some time now. Over the last years, I have written two ebooks about it and released a course platform for learning React and its ecosystem. The course platform is even built in React and Redux. My personal learnings are subjective, but I thought they may help people to learn or advance in React and Redux as well. Redux is not strictly coupled to React, but it happens to be that a lot of people are using both libraries in combination.

The article gives you recommendations to get started in React (and Redux) in 2018. I have written the article last year and a lot of people saw it as an helpful resource to get into React. Now, I have updated it for you to get you started in React this year.

The article is opinionated, maybe it doesn’t match every time your thoughts, but I hope to get feedback on it to improve myself as well. If you are not into React or Redux, you can still read the other part of the article. Feel free to give feedback, suggestions and improvements. Submit your own tips directly on GitHub.

Table of Contents

Tips to learn React

The section gives helpful advice to get you started in React. It should give a couple of answers to common questions such as: What are the requirements to learn React? What’s the best starter project in React? And do I need to know about JavaScript ES6? You will find all the answers about those questions in the following section.

Choosing a React Boilerplate Project

You are about to learn React? There are plenty of boilerplate projects out there to get you started with your first React application. A boilerplate project comes with its own opinionated tooling (Webpack, Babel, …) and initial scaffold of the application. You clone the repository from GitHub and run npm install && npm start on the command line to install and start the project. However, a custom boilerplate project adds a barrier to learn React itself. It is opinionated and thus every boilerplate project out there is different. So it is difficult to sync the learning experience of all React newcomers by just focusing on learning React instead of the different and opinionated toolings around it.

So as a newcomer to React, you will not only have to deal with React but also with the tooling. Therefore my general advice for React newcomers is to avoid all the “custom” React boilerplate projects out there. It is already tough to learn React itself. So why should you bother with the tooling? Especially when someone else has set up the tooling for you, it gets tough to make your own adjustments to it. Instead, it can kill your momentum when it comes to learn React in the first place. But which boilerplate project should you use to learn React?

The create-react-app boilerplate project is the preferred way to bootstrap a new project in the React community. It is the official setup recommended by Facebook for React and it is a zero-configuration setup where all the tooling is hidden for you. You get a foundation to start your React application in a comfortable environment with the abitlity to just focus on learning React.

After a while, once you have learned the basic and advanced subjects in React (which takes a while, believe me), you may want to dig deeper and setup your own project without create-react-app. Then it is about time to get to know the tools around it. Eventually you will miss and install the tools in your own project that you have used in create-react-app. When you setup your own project from scratch, you get to know how the underlying things work together. It will maybe lead to your very own boilerplate project that you can reuse or others might reuse as well. That’s how all of the custom boilerplate projects for React where created in the first place (e.g. React Boilerplate by Max Stoiber). You can use boilerplate projects from other developers as blueprint to experiment for yourself. You can experiment with the tools in those projects, get to know which problem they might solve for you and use them yourself for your own (boilerplate) project.

  • avoid custom boilerplate projects
  • use create-react-app to focus on learning React
  • when you feel comfortable with React
    • get to know the tools in React applications by exploring other boilerplate projects
    • create your own boilerplate project and adjust it with every project you will implement in React

There are a couple of other “officialy supported” boilerplate projects for React out there. Once you have learned React and create-react-app, you could have a look into Gatsby.js (for a static site generator for React) and Next.js (for server-rendered React applications).

Learn X before you learn Y

There are not only things to learn in React, but also for the ecosystem around it. React is only a view layer library and thus you come across the one or other library to complement your React application eventually. It can be quite overwhelming, especially when you come from a all-in-one framework solution such as Angular. But you shouldn’t see it as barrier to get started in React. You should embrace it as playground full of opportunities to complement your React application.

In general, you should learn plain React first and then learn more about the ecosystem around it. That’s where React is X and its ecosystem is Y in the “Learn X before you learn Y”-equation. But it goes far deeper into the sole building blocks of each solution. Experience how React and its ecosystem can help you to solve problems for you that would be difficult to address in vanilla JavaScript.

The ecosystem around React is huge since React is only a view library. There are a lot of opinions out there how to approach learning it. The general advice is to learn X before you learn Y. In the following list, you will find a couple of things to learn in React before you start to use another tool in the ecosystem:

  • JSX syntax
  • conditional rendering
  • ReactDOM.render
  • props and state
  • lists and keys
  • React’s local state management with this.setState() and this.state
  • unidirectional data flow
  • lifecycle methods
  • events and forms
  • component declarations (ES6 class components, functional stateless components)
  • children
  • composeable and reusable components
  • fetching data
  • higher order components

That’s how you will learn about React in the Road to learn React. The general advice is to learn React properly before you dive into the next topic. I guess there are way more “Learn X before learn Y”, but you should always keep in mind: Don’t learn everything at once.

When and how to learn Redux?

Learning is about keeping a state of flow. You need to adjust the challenges - the problems you are going to solve - to your level of skill. Only then you can grow your abilities with a stable momentum and enjoy learning. Otherwise, when setting the bar too high by learning too many things at once, you will get frustrated and quit.

Too often React and Redux are learned together. That’s not the best way to approach it. There is a high liklihood that it turns out to be too overwhelming because both of them come with their own individual philosophies. It is challenging to learn both at once and thus a lot of people quit learning React. Hence the common sense is to learn React first. You should feel comfortable in implementing applications in plain React. Embrace React’s local state management and experience the problems that might be solved by a state management library. Maybe you don’t need Redux at all.

There are many things to learn in React before using Redux for the first time. For instance, did you know about React’s Provider Pattern? In general, before you introduce a state management libary, using React’s local state should become uncomfortable. You need to experience the problems in a scaling application when using only React’s local state. Only by knowing about those problems, you will know what a state management libarz such as Redux can solve for you.

You can scale your React application a while before you run into state management issues. Maybe you never run into those issues, because your application is doing well with React’ local state. But maybe it will not suffice eventually. Then it’s about time to introduce a state management library such as Redux. But never replace React’s local state completly with Redux!

What about JavaScript ES6 and beyond?

React fully embraces JavaScript ES6. But it is as novel as React itself. Again, it can be difficult to learn both subjects at once. However, since it feels natural to use JavaScript ES6 in React, I don’t recommend to learn React with JavaScript ES5. You should try to learn about JavaScript ES6 along the way when learning React. In “the Road to learn React”, you will transition smoothly from JavaScript ES5 to JavaScript ES6 while implementing your first React application.

However, you could already learn ES6 in other JavaScript projects before using React. It isn’t coupled to React at all. My recommendations:

  • when you come from another JavaScript ecosystem (e.g. Angular)
    • learn ES6 in your familiar ecosystem where you feel comfortable
  • when you are a beginner in JavaScript
    • learn JavaScript ES5 properly
    • learn JavaScript ES6 along with React
  • when you are advanced in JavaScript
    • learn JavaScript ES6 along with React

When learning React, you should know or learn about those JavaScript ES6 and JavaScript Next features along the way:

  • const and let
  • arrow functions
  • object and array spread operators
  • destructuring
  • template strings
  • modules (import and export statements)

After all, you should be comfortable in JavaScript ES5 when learning React. You will use JavaScript along with HTML in React’s JSX syntax. For instance, there is no HTML attribute to iterate over a list of items. You would simply use JavaScript’s built-in map function to accomplish the rendering of multiple items.

const list = [
  {
    title: 'React',
    url: 'https://facebook.github.io/react/',
    author: 'Jordan Walke',
    num_comments: 3,
    points: 4,
    objectID: 0,
  },
  {
    title: 'Redux',
    url: 'https://github.com/reactjs/redux',
    author: 'Dan Abramov, Andrew Clark',
    num_comments: 2,
    points: 5,
    objectID: 1,
  },
];

class App extends Component {
  render() {
    return (
      <div>
        {list.map(function(item) {
          return <div>{item.title}</div>;
        })}
      </div>
    );
  }
}

That’s why it makes so much sense to learn vanilla JavaScript before starting with React.

What else to learn before starting with React?

Apart from having a basic understanding about HTML, CSS and JavaScript ES5, you should have a decent web development setup on your machine to support your workflow. At least, you will need a terminal and editor (or IDE). In addition, you can setup Git and GitHub. It would help you to keep track of your own projects and to clone projects from other developers from GitHub to explore their applications.

When I learned JavaScript, there weren’t much resources out there to learn about it. Nowadays, it is quite the opposite where it becomes difficult to choose a proper learning resource for JavaScript before learning React. There are a lot of high quality yet free resources out there to learn and advance in JavaScript. A couple of my favorites are Eloquent JavaScript, You don’t know JavaScript and MDN JavaScript documentation. But there are so many more.

Excerpt: React Components

The following section is only one excerpt about a subject that you will learn in React: components. It is not exhaustive, but it should only demonstrate you how powerful yet fine nuanced working with React can be. Even though React is only a view layer libary, it should make you aware about how fine-grained the library is in its usage. That’s why you should learn plain React first. The following chapter gives you only an idea about React components.

React Component Declarations

Often newcomers in React have a hard time with the different ways to declare a component. That’s because there are tons of (outdated) articles out there using different component declarations. React evolved naturally over the time and thus it changed with recent JavaScript versions (e.g. JavaScript ES6). It’s worth to have a look into React’s history of component declarations.

// React.createClass
var TodoItem = React.createClass({ ... })

// React ES6 class component
class TodoItem extends React.Component { ... }

// functional stateless component
function TodoItem() { ... }

There are React.createClass, React ES6 class components and functional stateless components. React components evolved from the former one to the latter one. Nowadays, only React ES6 class components and functional stateless components are used. So when to use which component declaration?

Functional stateless components have no lifecycle methods and thus no state at all. They are only functions that take state as input and have elements as output.

(State) => View

They are the most lightweight component. They are only a function in JavaScript and don’t add any boilterplate to the component. In addition, they don’t hold any local state and you cannot access the properties of the component by using this. A good rule of thumb is to use functional stateless components whenever you can over ES6 class components.

If you need to access a lifecycle method, need to hold local state (this.state) or need a component reference (this.ref), it would be the right time to use a React ES6 class component instead of a functional stateless component. There you have access to lifecycle methods and the local state of a component. It will often happen that a functional stateless component of yours will mature to an ES6 class component, because it needs to handle local state or needs to have access to lifecylce methods. But it can also evolve the other way around, from a ES6 class component to a functional stateless component, because you lift your state.

After all you should avoid to use React.createClass. It was used in JavaScript ES5, but Facebook declared it as deprecated in favour of ES6 class components.

I can recommend to read some very well written blog posts about React component declarations by James Nelson and by Todd Motto.

Lightweight Functional Stateless Components

It is absolutely fine to have multiple components side by side. Consider you want to implement a TodoList component.

function TodoList({ list }) {
  return (
    <div>
      {map(list, (item) => <div>{item.name}</div>)}
    </div>
  );
}

Rather than that you could split it up into multiple functional stateless components.

function TodoList({ list }) {
  return (
    <div>
      {map(list, (item) => <TodoItem item={item} />)}
    </div>
  );
}

function TodoItem({ item }) {
  return <div>{item.name}</div>;
}

The example is too small to see the immediate benefit. But when you split up your components you support readability, reusability and maintainability. Since functional stateless components have no boilerplate, it is effortless to declare multiple components. You should use lightweight functional stateless components whenever you can.

Concise Functional Stateless Components

You can use JavaScript ES6 arrow functions to make your functional stateless components more concise. Imagine you have the following Button component.

function Button({ onClick, children }) {
  return (
    <button onClick={onClick} type="button">
      {children}
    </button>
  );
}

Now you can use a JavaScript ES6 arrow function to make it concise.

const Button = ({ onClick, children }) => {
  return (
    <button onClick={onClick} type="button">
      {children}
    </button>
  );
}

The arrow function without a block omits the return statement.

const Button = ({ onClick, children }) =>
  <button onClick={onClick} type="button">
    {children}
  </button>

The conversion enforces to only have props as input and an element as output. Nothing in between. That makes the component even more lightweight. Still, you could do something in between by using a block body for your arrow function.

const Button = ({ onClick, children }) => {

  // do something

  return (
    <button onClick={onClick} type="button">
      {children}
    </button>
  );
}

After all, JavaScript ES6 arrow functions help you to have even more lightweight functional stateless components. That’s one example where you can see how JavaScript ES6 fits naturally into React.

Presenter and Container Components

In React a component is a representation of your state. It is a good approach to think of it as (State) => View. Additionally, a component can have event handler to change the state and trigger a re-rendering. Since the representation of the view derives from the state, the view changes when the state changes. I can recommend the Presenter and Container pattern for a scalable component hierarchy. While one part of the components represents the state, the other part derives and changes the state.

In presenter components, you avoid to have any logic. Keep your components dumb and only pass properties and callbacks to them. Most of your components don’t need to know everything. These components should be most of the time functional stateless components. You can keep them pure and remove any side effects. A pure component means that the view will be always the same when using the same props as input.

In container components, you prepare the data and callbacks for your presenter components. Even more you can pass dependencies or business logic to your presenter components. Container components are most of the time ES6 class components which handle lifecycle methods or manage local state.

In Redux, a more specific name for a container component is a connected component. These components are connected to the Redux store to derive and manipulate state via the Redux store.

Container components care about how things work. Presenter components care about how things look. You might want to have a more in depth read about the topic by Dan Abramov.

When to use Container Components

You are using the Presenter and Container Components, but you are not sure when to use which component? I can recommend to start with a Container Component at the top of your application as parent component followed by a bunch of Presenter Components as child components. While the parent component cares about how things work, all children care about how things look. After a while, you will notice that you pass too much properties and callbacks from the parent component to its children. Moreover, you pass most of the things several component layers down. Then it’s time to introduce Container Components in between your Presenter Components.

It’s a good rule of thumb in general to stick to presenter components and add only a bunch of container components later on. But where to put the container components?

Rule of thumb 1: If your parent Container Component deals with state alone, you can evaluate your Presenter Component hierarchy below. You might notice that a subtree of your presenter components deals with a substate which is not used by other components. Find the parent component of this subtree and give it a Container Component to deal with the state management of the subtree. Your parent Container Component will get lighter, because it doesn’t have to deal with all of the state.

Rule of thumb 2: Some of your presenter components might get a bunch of well prepared properties or callbacks for only themselves. Start to give them a Container Component to deal with the logic and make your parent Container Component more lightweight again.

Write your first higher order component

Imagine you want to display a list of items, but you have to fetch the items asynchronously first. Now you will need a loading indicator to show your pending request. After the request fulfills, you show the list of items. Dan Abramov explains in an egghead.io lesson how this works.

But you could go one step further by introducing your first higher order component. A higher order components (HOC) returns a component with enhanced functionality. Your HOC could have the name withLoadingSpinner and your component to enhance could be ListItems. The enhanced version of the component shows either a loading indicator or the list items.

// HOC declaration

function withLoadingSpinner(Component) {
  return function EnhancedComponent({ isLoading, ...props }) {
    if (!isLoading) {
      return <Component { ...props } />;
    }

    return <LoadingSpinner />;
  };
}

// Usage

const ListItemsWithLoadingIndicator = withLoadingSpinner(ListItems);

<ListItemsWithLoadingIndicator
  isLoading={props.isLoading}
  list={props.list}
/>

For instance, similar higher order components are used in a real world SoundCloud application.

Higher order components are powerful. You should use them with purpose. Always remember that they might add another level of abstraction which makes it hard for other developers to understand your component hierarchy.

Recompose offers a great range of helpful higher order components. Before you start to implement your own higher order components in React, have a look at the recompose library. It may already solve your issue. But invest a couple of minutes to explore how these higher order components are implemented.

Conditional Style in React

Maybe you came across the problem to have conditional class attributes in your React components. It would look similar to the following:

var buttonClasses = ['button'];

if (isRemoveButton) {
  buttonClasses.push('warning');
}

<button className={buttonClasses.join(' ')} />

The className attribute would resolve into ‘button warning’ if the isRemoveButton predicate is true. For the case of conditional class attributes in React, there exists a neat little library called classnames.

var buttonClasses = classNames(
  'button',
  {
    'warning': isRemoveButton
  },
);

<button className={buttonClasses} />

It becomes effortless to apply conditional style on elements.

Animations in React

I was hooked when I saw an animation in React for the first time. There are a couple of libraries out there helping you with animations in React. For instance, React Motion gives you a toolkit to implement animations in React. Personally I found the learning curve pretty steep and I struggle every time again when I use it, but it pays off once you see your first smooth drag and drop animation.

Resources to learn React

After all, how to start learning React? What are the best courses, tutorials and books out there? Personally, I recommend everyone to go through the official React documentation and tutorial. The maintainers and contributors behind React improve it every day and put a lot of effort into it. So it should be a great way to get a first impression about React before choosing it as your next thing to learn.

After that, to get an broader impression about React, checkout the free ebook The Road to learn React. It teaches only plain React by building one larger React application from scatch; basically from idea to deployment. Along the way, you transition smoothly from JavaScript ES5 to JavaScript ES6. I am biased here, because I have written the ebook, but I am proud to see a lot of people learning React with it. So far, more than 13.000 people downloaded it and at this time it gets translated into 6 languages (Portuguese, Spanish, Korean, Italian, Russian, Simplified Chinese). It evolved over the last year from 90 to 190 pages and gets improved by me and the community as often as possible. Thus after only 12 months, it is in its 4th edition.

Build a Hacker News App along the way. No setup configuration. No tooling. No Redux. Plain React in 190+ pages of learning material. Pay what you want like 14.500+ readers.

Get the Book

It shouldn’t take you too long to get through the ebook. After that, you can expose yourself to more React by taking other courses or by building a couple of applications in plain React yourself. Once you finished “The Road to learn React”, I give a couple of recommendations how to continue learning React.

Tips to learn Redux

React and Redux are often used together. Redux is the successor of the flux pattern and is widely used in the React community. But it is not strictly coupled to React.

Before we dive into Redux, I just wanted to add “You might not need a state management library”. Everyone is speaking about state management libraries like Redux and MobX. Don’t introduce them too soon. You should read You might not need Redux by Dan Abramov.

You are still learning React? Use setState to manage local state. Once you feel comfortable in using React, you might come across problems like sharing state across multiple components. Even then you don’t necessarily need an external state management library. You can lift state up or down.

In a growing application, there will come the time to introduce a state management library eventually. A part of the article Redux or MobX: An attempt to dissolve the Confusion covers how to approach to learn state management in React.

The following sections will give you a couple of hints on how to use Redux in React.

Global State Everything

Not everything belongs in your global Redux state. Components should hold local state in React too. That’s why it is important to learn React’s local state before using Redux. Otherwise, you are going to store everything in your global state with Redux. Think about a large scaling application in a growing team of developers. You don’t want to have all of your view states, such as a toggled checkbox or opened dialog, in your global state. The respective React components should deal with it. Scaling state management is a balancing act between React and Redux.

Folder Organization

I can recommend the article by Jack Hsu which suggests a way to organize your code in a scaling application.

First key takeaway: folder organization by feature.

React + Redux tutorials always show a technical separation of folders. It is a good approach to learn React + Redux, but putting all your reducers and actions into one dedicated folder doesn’t scale for everybody.

src/
--actions/
--reducers/
--components/

The often heard recommendation is to have feature folders. Each folder can have reducers, actions and components itself. An example folder structure for one feature could be:

message/
--components
--reducer.js
--actions.js

A more elaborated example with container, presenter and test files is:

message/
--components/
----messageItem/
------presenter.js
------spec.js
----messageList/
------container.js
------presenter.js
------spec.js
--reducer/
----index.js
----spec.js
--actions/
----index.js
----spec.js

I know for sure that not everyone does agree with it. Especially hiding reducers in a feature folder is not following the Redux intention to have them globally accessible. The recommendation is to abstract reducers properly in the first place to share their functionalities. But in a realistic scenario with multiple teams working on one application under time pressure, there isn’t always the opportunity to have the correct abstraction in the first place. In a scaling app you are often relieved to have an encapsulated feature module.

Second key takeaway: clear boundaries of feature modules.

A module should always have an index.js file as entry point. The index.js only exposes an API (What’s an API?) which should be public to other modules. In React + Redux an index.js file could export container components, maybe presenter components, action creators to be called from somewhere else and last but not least the reducer. In our more elaborated example we would have to add an index.js file at the top. Maybe also in our component folders as well.

message/
--index.js
--components/
----messageItem/
------index.js
------presenter.js
------spec.js
----messageList/
------index.js
------container.js
------presenter.js
------spec.js
--reducer/
----index.js
----spec.js
--actions/
----index.js
----spec.js

The feature module index.js could have the following content:

import MessageList from './messageList';

export default MessageList;

export MessageItem from './messageItem';
export reducer from './reducer';
export actions from './actions';

Now every foreign feature module should only access the message feature module by its entry point.

// bad
import { reducer } from ./message/reducer;

// good
import { reducer } from ./message;

Both key takeways, feature modules and clear boundaries, help you to organize your code.

Naming Conventions

Naming can be one of the most difficult things in software engineering. A proper naming convention is a best practice in order to have maintainable and comprehensive code. React + Redux offers a lot of constraints where to organize your code, but is not opinionated about naming. Whether your function resides in a reducer or component, is an action creator or selector - you should have a naming convention for it. You should have it before you scale your application, otherwise you end up with untraceable callbacks and refactorings. I am used to have for each type of function a prefix.

In a component a callback comes with the little word on as prefix (onCreateReply). The prefix in a reducer to change the state is apply (applyCreateReply), in a selector it is get (getReply) and in a action creator it is do (doCreateReply). You don’t need to follow these recommendations, but I would suggest to follow your own naming conventions at least.

Tracing State Changes

In a growing application with plenty of actions you want to have traceable state changes. One neat helper to see all of your state changes is redux-logger. Each logging shows the previous state, the action and the next state.

But you want to ensure that your actions are recognizable. Therefore I recommend to have prefixes for your action types.

const MESSAGE_CREATE_REPLY = 'message/CREATE_REPLY';

Now whenever you create a message reply, you will see the logging message/CREATE_REPLY. In case of a state bug you can quickly trace the faulty state change.

Keep Your State Flat

In Redux you want to have a flat state. It keeps your reducers simple, because you don’t need to change properties deep down in your state object. It is easy when you are allowed to mutate your state directly. But you are not allowed to do so in Redux, because the state is immutable.

It happens often that you only implement the frontend application. You need to deal with backend data structures as they come. Sometimes entities are nested into each other. Imagine a list of blog post entities, which can have an author entity and a list of comment entities.

{
  post: {
    author: {},
    comments: [],
  }
}

Most of the entities will come with an id.

{
  post: {
    id: '1',
    author: {
      id: 'a',
      ...
    },
    comments: [
      {
        id: 'z',
        ...
      },
      ...
    ],
  }
}

It makes sense to normalize the data to make the state flat. The normalized data references each other by id. Afterwards you can save them by entity type to easily look them up by id and reference.

{
  posts: {
    1: {
      authorId: 'a',
      commentIds: ['z', ...]
    }
  },
  authors: {
    a: {
      ...
    }
  },
  comments: {
    z: {
      ...
    }
  },
}

The data structure is not deep nested anymore. It is easy to keep it immutable while you apply changes. Normalizr is a powerful library, which helps you to normalize your data.

Single Source of Truth

Normalized data helps you to keep your state in sync. Imagine again the backend request returns a deep nested data structure of blog posts. A blog post has an author, a list of comments, but this time each comment has an author as well. The comment author can be the same as the post author.

{
  post: {
    author: { id: 'a' },
    comments: [
      {
        author: { id: 'b' },
        reply: {},
      },
      {
        author: { id: 'a' },
        reply: {},
      },
    ],
  }
}

You can see that a blog post author has written a comment too. Thus we have the object two times in our nested data structure. There is no single source of truth. It makes it difficult when you want to modify the author.

When you treat your data as normalized data, the author is only one entity. It doesn’t matter if it is a blog post author or comment author. The author is one single source of truth in your entities of authors.

{
  authors: {
    a: {},
    b: {},
  }
}

Since your blog posts and comments still have the author ids as reference, it is fairly easy to display the author in the lists of blog posts and comments.

Whenever you modify the author, all references will get updated. Imagine you could follow an author. You can easily update the one entity - the single source of truth.

{
  authors: {
    a: { isFollowed: true },
    b: {},
  }
}

All author representations in your lists of blog posts and comments are updated, because they are only references to one source of truth.

Selectors

You don’t use selectors yet? It is totally fine to have prop computations in mapStateToProps of Redux.

function mapStateToProps(state) {
  return {
    isShown: state.list.length > 0,
  };
};

Once you introduce selectors, you can move the computations into your selectors and keep your mapStateToProps tidy.

function mapStateToProps(state) {
  return {
    isShown: getIsShown(state),
  };
};

Later you could have a look into reselect. It helps you to compute derived data from your state and gives your application a performance boost.

  • Selectors can compute derived data, allowing Redux to store the minimal possible state.
  • Selectors are composeable. They can be used as input to other selectors.
  • Reselect Selectors are efficient. A selector is not recomputed unless one of its arguments change.

Refactor, refactor, refactor

There will come a time when you only want to refactor your code. It doesn’t matter if you are only using React, React and Redux or some other library or framework. Everyday you will learn a more elegant way of writing your code or a novel pattern to apply.

Once you have a larger component tree in React, you may see patterns to distribute containers among presenters in a more elegant way. You will see abstractions in container and presenter relationships and vice versa. If you didn’t apply proper naming conventions in your code base, you may want to introduce them.

There will be always something to refactor to keep your code more maintainable and readable. You should take the time to apply these refactoring, especially naming conventions, in an early stage of your project.

Generators, Sagas, Observables, Epics, ...

Redux is a great library to experience different paradigms and technologies. People are building libraries for async Redux actions. They use different approaches to deal with those side effects:

As a beginner it makes sense to stick with Redux Thunk. As you advance in the ecosystem, you could have a look at other libraries. Redux Saga is one of the most adopted approaches. But also Observables are used more often. Overall the Redux ecosystem itself is a perfect place to explore the JavaScript ecosystem.

Learn about implementation details of Redux

The whole Redux source code isn’t much to read. Once you are familiar with Redux, you should give it a shot to read the source code.

In the beginning it may be easier to get started by watching the Getting Started with Redux video series by Dan Abramov. For instance one video explains how to implement the createStore from scratch, while another one explains how to implement combineReducers from scratch.

In the second video series Building React Applications with Idiomatic Redux by Dan Abramov you will learn how to implement an own middleware from scratch. Once you have your own middleware implemented, you want to let your store know about it. After that you get to know that there is already a Redux helper applyMiddleware to wire all your middleware to your store.

Both video series will not only help you to learn Redux, they will also help you to learn about the inner workings of Redux. After that you are prepared to dive into the source code.

Tips for Testing

There exist some tool combinations to test your JavaScript code nowadays. It can be Mocha/Chai or Karma/Jasmine. The latter can be found a lot when testing Angular code, the former you will find when testing React apps. Airbnb introduced a popular library to test React components called enzyme. Another way to test is Jest by Facebook.

A lot of people think you should use one or the other, but you can use enzyme and Jest together. Especially the snapshot testing in Jest complements enzyme. Both libraries are the de facto standard in testing React.

Sinon is a great addition to spy, mock and stub functions in your tests.

I can recommend to read some articles about testing like the one by A. Sharif.

Unit test often, integration test rarely your components

Enzyme allows you to conduct unit and integration tests of your components. There are three options available to render a component.

While shallow() only renders the component without children, mount() renders all child components as well. The first is used for component tests in isolation (unit tests) and the latter is used for integration tests. Integration tests are more likely to break, because they include a bigger set of your component tree. The maintenance costs are higher for integration tests. You should have a lot of small maintanable unit tests, but a few vital integration tests.

The third option in enzyme is render(). Render similar to mount() renders all child components. But with mount() you have access to components lifecycle methods like componentDidUpdate.

I very much like the rules of thumb by Geoffroy Warin:

  • Always begin with shallow
  • If componentDidMount or componentDidUpdate should be tested, use mount
  • If you want to test component lifecycle and children behavior, use mount
  • If you want to test children rendering with less overhead than mount and you are not interested in lifecycle methods, use render

Keep your tests minimal and simple

Otherwise you will end up with high maintenance costs.

Check if a component renders in an unit test. Check if the correct props and callbacks reach a child component in an integration test.

In order to keep your component tests minimal and simple you have to be familiar with your selectors. Enzyme offers a range of selectors to dive into your component tree.

Test callbacks with a library like sinon. Avoid to test business logic in components, since this might be not the best place anyways. In a service the business logic would be decoupled from the component and should be tested.

After all Facebook introduced Jest to keep your tests lightweight in the first place. You can easily set up a Snapshot test. Then the test will fail when the component output changes. You can either accept the change or investigate in the error.

Embrace TDD

Everyone is saying that you should do test-driven development (TDD), but nobody is doing it. I think that once you found out how to test each part in your React + Redux app, you can easily apply TDD. You will notice that a reducer test reads differently than a component test, but each type (reducer, component, …) of test will always follow the same test pattern.

Take a reducer test for instance, where you always want to expect that reducer(state, action) === newState. The pattern is always the same: (input) => output without side effects. The test has an initial state, an action with action type and payload and an expected new state.

Additionally the test has to make sure that the state is immutable - I recommend to use a helper like deep-freeze. In pseudo code the test would always read like the following:

const initialState = { ... };
const action = { type: ..., payload: ... };
const expectedState = { ... };

deepFreeze(initialState);

expect(reducer(initialState, action)).to.equal(expectedState);

Once you know the test patterns for each part in your app, you should apply TDD. People tend to use code snippets for that task, which I can totally recommend. Add a snippet for each test part, like the one blueprint from above for reducer tests, in your app.

Test Multiple Components

I believe it is fine to export multiple components from one file for the sake of testing. Each component could get unit tested with enzyme shallow, but one could also integration test them all together by using enzyme mount for the upper parent component. Additionally it should be mandatory to have a Snapshot test with Jest for each component.

General Recommendations

In the end I have some general recommendations for the React and Redux environment.

On-boarding

Your whole team is new to React?

Since React is a library, but the ecosystem around it could be seen as flexible framework, don’t add extensions too fast. Every time you introduce a new module, raise awareness in your team. Especially when coming to the Redux ecosystem itself, there is an overwhelming amount of smaller modules. For instance:

  • Don’t add redux-actions before people wrote their own action creators and reducers
  • Don’t add redux-forms before people wrote at least one own form and validation
  • Don’t add reselect before people wrote their own selectors
  • Don’t add recompose before people wrote their first HOC

Follow best practices by thought leaders. Establish your own best practices. But make sure that everyone understands them. Define clear naming conventions and folder structures. Don’t discuss those topics too late in the migration phase.

Moreover address certain topics more in depth. For instance:

  • Which Redux side-effect library do you want to use?

You can explore observables or generators, but not everyone might be aware of these novel features in JavaScript. Make sure that everyone is fine to use it. Otherwise you will only end up to add another level of complexity by using generators or observables.

Stay Curious

In the React + Redux ecosystem there is a set of great contributors who embrace novel things. Don’t be dogmatic about the way you implement something, embrace new ways of doing it! There are great articles which describe these novelties. Have you ever seen composed components with ramda.js in React and Redux? Have a look at The elegance of React by A. Sharif. Stay curious!

Dive into other environments

The ecosystem offers so much more. You are already familiar in React? Start to build your first mobile application with React Native or your first desktop application with Electron. The possibilities are endless, but don’t overwhelm yourself when you are a beginner.

No Silver Bullet

React or Redux are not the silver bullets for everything. There are other solutions to give a shot.

Don’t see React + Redux as dogma. Both are exchangeable. MobX can be an alternative to Redux for state management. In a larger code base it is still possible to exchange the state management layer.

React is only the view layer. You can exchange it with a more other solution like Preact or Inferno.

After all this shows the ultimate power of the whole ecosystem which contains building blocks as solutions for different problems.

Airbnb Style Guide

Code style is very important. In a team of developers you want to embrace one common code style to understand each others code. The source code might be revisited by multiple people over time and thus nobody wants to deal with code which only one developer understands. Additionally the on-boarding for new developers will go more smoothly.

The team should embrace to follow an common standard rather than developing an own code style. Therefore I can recommend the Airbnb JavaScript Style Guide for general JavaScript, but also the Airbnb React/JSX Style Guide. Both are commonly used guidelines for JavaScript and React developers.

No style guide will help your team without enforcing it. You can use ESLint to follow both mentioned style guides.

Contribute!

The ecosystem is huge and there is a lot potential to contribute in the open source community. You don’t need to deep dive into a library, but can also contribute in documentation or open source applications as beginner. Start by applying the gathered best practices in an application like favesound-redux, which I wrote myself to demonstrate React + Redux. You feel more confident? Have a look into the endless selection of libraries in the React + Redux ecosystem.

Honor the Contributors!

Behind every library there is a person or team of contributors and maintainers. Most of them are doing the work on a library in their spare time. Honor their work and avoid to take it as granted! It is a gift from other developers who care about the community and open source their work. You can even help them to improve the library by giving constructive feedback, opening issues with well written instructions or by contributing with Pull Requests. After all it simply helps to write a kind message to remind these people that you are using their open source contribution for your own project. It encourages them in their work.


What’s missing in your opinion? Where do you agree or disagree? As I said, it’s a list made up of learnings and personal opinions. But I am keen to hear your feedback. You can have a direct impact on the article and submit your tip.

Build a Hacker News App along the way. No setup configuration. No tooling. No Redux. Plain React in 190+ pages of learning material. Learn React like 14.500+ readers.

Get the Book
comments powered by Disqus

Never miss an article about web development and self-growth.

Take Part

Join 8600+ Developers

Learn Web Development with JavaScript

Tips and Tricks

Access Tutorials, eBooks and Courses

Personal Development as a Software Engineer