Understanding a Simple React, React-Router and Redux Application in ES2015. Part 2

react-eco-wp

This is the third article in a series of posts on react, redux and webpack. Others:

  1. configuring webpack
  2. Understanding a simple react, redux and react-router app in es2015, part1.

Here, we will cover the routes configuration, the actions and all the react components starting from the Root.

Root

If you remember from the last post, the Root component is called inside of index.js, the entry point to our app. It receives redux’s store and the browser history as props.

If you open app/containers/Root.js you will see the same as configureStore, namely, a conditional to see what environment you are in. Let’s check out the dev version:

Lot’s of imports here:

  • from react we import the Component and PropTypes objects. The Component object is what we extend when creating a react component. The PropTypes object is used to reinforce types in our props, i.e. passing a string when an array was expected will throw a warning in the console. We also need the react lib itself, removing it will give an error.
  • The provider from react-redux is a utility higher-order component to make the store available to all components inside who wish to subscribe to it.
  • Devtools is the monitor we see when we run the app, docked on the right. It shows us the current and past states.
  • Router from react-router. This is the component where we will configure our app’s routes.
  • Routes are our app’s route. We will check them out later.

All our Root component does is wrap our app around the Provider component. We render the Router inside of it, along with the DevTools (if we are in a dev env).

Router

Open up /app/routes.js. This is where you distribute your app into routes. It’s also the place where you decide what component goes with what route.

Our app is pretty simple: our root path belongs to the App component. Then we have two routes inside of our root: and index and “/about”. This means whatever route we are in, “/” or “/about”, our App component will always render.

React will only render FilterableTable if we are in the root path “/”. The same logic applies to About.

App

Go to /app/components/App.js

If you’re asking yourself why our components are divided into the /components and /containers directories. Then have a look at this part of the redux docs. Basically, the components directory holds the “dumb” components, those that are not aware of redux and its store. They only receive props and care about presentation. The components inside /containers are aware of the app’s state as they are connected to the redux store.

This App component is available everywhere so it’s smart to put things like site navigation in here. That’s why we put a footer with the two routes we have. You must also pass in the children prop, which references the components that must be rendered inside the App for a given route.

If you navigated to “/about”, the children component will actually be the About component. React-Router, for good or bad, abstracts all of this. That’s why we must take care when we define our routes.

FilterableTable

Open up /app/containers/FilterableTable.js

We import connect from react-redux. This function connects or subscribes a component to the store, making it aware of any changes to the state.

We also import filterTable from our actions. This function is really simple:

It takes the current filter and return and action object with the action type and that filter. This action object gets sent to the reducer so the reducer can compute the next state.

We define a component called FilterableTable. It has an input where you can filter the ProductTable. Basically, whenever there’s a change in the filter, the state changes, so the ProductTable component reacts to that and changes accordingly.

It receives 2 props, filter and onFilter. Where are this props coming from? They are certainly not from the app component, nor from the router. They come from the connect function of react-redux. This function acts as a wrapper. Check out the last lines of FilterableTable. We are not exporting the FilterableTable component directly, we are actually exporting a wrapper of that component.

The wrapper takes 2 params when being created: mapStateToProps, and mapDispatchToProps.

With these 2 params, you can map which part of the state you want to make available to the component (FilterableTable), as well as which actions.

When we call connect(mapStateToProps, mapDispatchToProps) we are configuring the wrapper component, and we pass in what part of the state we want to know about, and which actions we want present so that we can dispatch them to the store.

When we do   connect(mapStateToProps,mapDispatchToProps)(FilterableTable);We are doing the above mentioned, configuring the wrapper component but also creating it by passing in the FilterableTable component. Internally, its probably dong something like this:

In short: when dealing with containers, we export a wrapper function (i.e. the container) and pass in the component that should receive the state and callbacks it needs.

Note: Normally you would have the FilterableTable component in another file, under the components directory. You would only need to have the mappings and the connect in this file (basically the wrapper). I just like to have it on the same file to better understand what’s gong on, specially if it’s not too big.

ProductTable

/app/components/ProductTable.js

This component’s only concern is to show the ProductRows that should be visible under the current filter. It does this by comparing the filter with every product name, using javascript’s indexOf function. It only pushes the matching ProductRows to the array that will later be used to show the products.

Note: the products array doesn’t really belong here, it should be in a database, but you already knew this.

ProductRow

Easy stuff, this component’s only concern is to show the product row: name and price.

 

 

Author: JP

Javascript jedi padawan.

  • Sams

    Hi man!
    Thanks for that nice article.
    I’m new guy in React, so please explain – where is React.createClass()
    Why don’t you use it?
    How to implement componentDidMount()?
    Thanks!

    • Jean-Pierre Sierens

      Hello
      You’re welcome!

      React.createClass is a method for when you are using the old way of creating react components. In ES6+ (the new javascript) you can create react components the following way:

      ‘class someComponent extends React.Component {}’
      The above creates a class that extends the Component class from the React lib, this is where you define your component and methods like render() or componentDidMount(). You can find an example of this on the Root.dev.js file.

      There is another way to create a react component. It’s what I mostly use in this tutorial: stateless components. stateless components are simplified react components, it’s when you don’t need to define any lifecycle methods, where you don’t define any state and also where you don’t need any context (this). Basically stateless components are dumb components who only care about presentation and executing callbacks when an event occurs. An example is the ProductRow component defined above in the article:

      const ProductRow = ({ data }) =>

      {data.name} = {data.price}
      ;

      It only cares about presenting the name and the price of the product, so we can just define the component as a function.

      Here’s an article on how to do React with es6+
      https://babeljs.io/blog/2015/06/07/react-on-es6-plus

      Here’s a section on stateless components:
      https://facebook.github.io/react/docs/reusable-components.html#stateless-functions

  • corey

    why are all the files .js instead of .jsx?

  • Cowboy_X

    Typo: “It takes the current filter and return and action object…”

    should read “It takes the current filter and returns an action object…”

    I spent about five minutes trying to figure out what that says…