After hearing a lot about React & Redux recently I decided to play around with it and try to build something to see what it's like. This article covers the things I've learnt so far and will give you the knowledge and foundations to build a basic application.

I'll assume that you have some JavaScript knowledge and I'll link to resources that I've found useful while learning. This will give you the chance to dive into topics further. After reading this you will have a clearer picture on what React and Redux is and how an application would fit together.

React

  • Is a view library, referred to as the V in MVC (Model View Controller).
  • Applications are made up of custom components created by you.
  • You can write components in JSX syntax
  • It uses a virtual DOM (Document Object Model), which is a lightweight version of the real DOM. Components will interact with the virtual DOM. The virtual DOM will check the differences between itself and the real DOM and only update the differences in the real DOM. Talking to the virtual DOM is less work that interacting will the real DOM directly, which gives the application increased performance.
  • Download the React Dev Tools extension when developing an application. It will give you a lot of helpful information.

Redux

Your application will have a store which will hold the state for your application. One of the principles of Redux is that your application will only have one store. The store is where you store the state for the whole application. You can think of the state as all the data/content for you app. In your component you will display data/content from the store.

  • It is a seperate tool from React and not required to build a React application.
  • Helps you manage your applications state.
  • You can use Redux with other frameworks but it works well with React.
  • There are lots of good tutorials on Redux. Wes Bos has a free tutorial series on Redux here and the creator of Redux, Dan Abramov has tutorials on Egghead.io.

Here's a quote from the Redux doc's that tells you how it works:

The whole state of your app is stored in an object tree inside a single store.

The only way to change the state tree is to emit an action, an object describing what happened.

To specify how the actions transform the state tree, you write pure reducers.

That's it!

One awesome feature Redux has is it's time travelling dev tools. It let's you jump forward and back to view your applications state at any one time. I'm not going to go into how to set it up in this article, but I recommend looking into it more.

There are three parts to Redux: Actions, Reducers and the Store. Here's how each part works:

Actions

  • Are a list of things it can do.
  • It doesn't know how to do the action.
  • It doesn't know anything about the store.
  • It knows what data it's been passed (action name & any other information you sent it).
  • It will say to the Reducer 'Hey I wanna do this and here's the data to do it'.

Reducers

  • Is a list of things it knows how to do.
  • Is always listening for actions and will act on ones it recognises.
  • Has access to the state in the store.
  • A reducer should run in this format:
    • Get a copy of the current state.
    • Do whatever it was asked to do.
    • Return a new version of the state.

Redux is immutable, meaning you should always return a new version of the state, instead of modifying the state.

Store

  • The store holds the current state.
  • There is one state for the whole application.
  • When the state changes, subscribed React components will update automatically.

Scenario

Let's go through a scenario and get an idea of how the redux event flow works. In the scenario, the electronic list will be our React component, you will fire an Action, Bill will play the role of Actions and Lucy will play the role of a Reducer.

There's a big event happening at your work and you want to invite your friend Sue. To do this, you will need to get her added to the attendee list. You ask around and find out that there is an electronic list. The list is always updated to the latest attendee information.

You walk up Bill and say I want to add an attendee called Sue to the events attendee list.

Bill only knows how to do get certain things actioned. He sees your request and walks over to where Lucy sits and says please add an attendee called Sue to the events attendee list.

Like Bill, Lucy only knows how to do certain things. When she gets asked to do things she doesn't know how to do, she ignores them. In this case she has heard Bill say add an attendee called Sue and she processes it. Lucy has been put in charge of all the event information, she knows how to update it. Lucy gets the attendee list and adds Sue to it. The event information is then dispatched out to the rest of the company and will send an update to anything subscribed to it, eg: the electronic list.

You look at the electronic list, see that it's been updated and that Sue is now on the list.

Build time

We are going to build an app which will take a list of attendee names and print each name on a 'hello my name is' badge. Each badge will be coloured in the attendees favourite colour. Once we get that working we will add the functionality to add and remove people from the list. Note that I'll be using some ES6 in these examples.

JavaScript Libraries we will be using:

Since we are focusing on JavaScript, we will use Foundation to take care of the styling for the app. There are some new ideas on how to style React components, one being CSS Modules which you can learn about here if you're interested.

React

Rendering our first component

We need a way to access functionality from libraries we are using. In the example below, we are storing the render method from ReactDom in a constant called render.

  const { render } = ReactDOM;

Render will take our React Component and render it as a DOM element. We will render our component to the HTML element with an id of app.

  render, react component, DOM element to render it into
render(<App />, document.getElementById('app'));

We create a React component called App. All components have a render function and return some HTML. You can only render one HTML element from a component.

This would be invalid and would throw an error.

  class App extends React.Component {
    render() {
        return (
            <h1>Attendees</h1>
            <p>Some text</p>
            <img src="http://placehold.it/300x20" />
        )
    }
}

Instead wrapping it inside of a div would make it valid.

  class App extends React.Component {
    render() {
        return (
            <div>
                <h1>Attendees</h1>
                <p>Some text</p>
                <img src="http://placehold.it/300x20" />
            </div>
        )
    }
}

Going forward our newly created App component will act as our root component. We will put any other components we create inside it.

See the Pen 1/4 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

Redux

Lets setup up Redux and pass the application some data. We will need to setup Actions and Reducers, as well as the Store for the app.

Actions

We will setup our react components to call an action when an event happens. We'll send any data we want to the Actions. The action will then send out a message to the Reducers, saying here's what I want to do and here's the data I've been given.

We currently don't need any Actions in our app so we'll leave it for the time being as a empty object.

  const actions = {};

Reducers

The Reducer has access to the applications state. It will accept two parameters, one is the state and the other is the action. Since we have no actions setup, all we need to do is return the state, as it will never change. Once we start adding Actions we will need to come back here and add functionality so it returns a new modified state.

  function reducer(state = [], action) {
    return state;
}

Store

As part of the setup, we will create a new component called AppContainer that will wrap around our App component. We'll use functionality from the React Redux in this part of the setup. This section here may be worth rereading once you've learned how the rest of the application works.

mapStateToProps function will subscribe the AppContainer component to any changes that happen in the store. Any time a change happens in the store, this function is called and the new stores state will be merged into the AppContainer component props.

mapDispatchToProps function will take your Actions and merge them into the AppContainer's component props, so we can call Actions from components.

  const AppContainer = connect(
    function mapStateToProps(state) {
        return {
            attendees: state
        };
    },
    function mapDispatchToProps(dispatch) {
        return bindActionCreators(actions, dispatch);
    }
)(App);

The bottom line in the example above is where we tell the AppContainer component to wrap around the (App); component.

createStore function will create a Redux store for the application. There should only be one of these and it will contain the state. We will pass our Reducers into it and the default state, which will be the attendee list.

  // createStore(reducer, defaultState);
const store = createStore(reducer, attendeeList);

As part of using React Redux bindings, we need to wrap our AppContainer component in a Provider tag. The Provider tag wraps our whole application. The AppContainer has access to the store through the connect() function.

  render(
    <Provider store={store}>
        <AppContainer />
    </Provider>,
    document.getElementById('app')
);

Component

When you write your react component, it will know nothing. It will just render the HTML that you wrote inside it's render function. You can pass your component data through props.

We will access the attendee list data using this.props.attendees, which we created in MapStateToProps. We will loop over it and render out each of the attendees names.

When we have dynamic content we will need to give items a unique identifier so React can work out what's what. We can do this by adding a key attribute to the list item key={index}. If you forget this, then you'll get a error in your console saying 'Each child in an array should have a unique "key" prop.'

Below you can see these steps working together to render the Attendee list.

See the Pen 2/4 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

Adding components

The next step is to display each attendees name in a 'hello my name is' badge. One way to do this would be to add the badge HTML to our App component. This would work but we want to have code that does different things separated. Instead lets create a new badge component, which will render the badge HTML.

  class Badge extends React.Component {

    render() {
        var style = {backgroundColor: this.props.attendee.color};

        return (            
            <div className="hello-badge" style={style}>
                <p className="hello-badge__title"><span className="hello-badge__hello">Hello</span><br /> my name is</p>
                <p className="hello-badge__name">{this.props.attendee.name}</p>
            </div>
        )
    }
}

You'll notice that we use ClassName="" instead of class="" this is because we are using JSX syntax. You can learn more about that here.

You'll also see that we are using the attendees favourite colour provided in the data to give each attendee their own coloured badge.

To use our new badge component we will need add it to our App component. Since our badge component knows nothing about the attendees we will need to pass in our attendee through props. We can access it inside the component using this.props.attendee (this.props.somethingWePassedIn).

  <ul className="attendees">
   {this.props.attendees.map((attendee, index) =>
       <li className="attendees__attendee" key={index}>
           <Badge attendee={attendee} />
       </li>
   )}
</ul>           

See the Pen 3/7 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

We will now refactor our app component slightly. Initially when we created it, it's responsibility was to be a wrapper for the application. It now has the responsibility of how to render out an attendee list. Lets create a new component called attendees, which will render the list. We will move our list HTML inside the new component and pass it the attendee list.

Our new App component is now simpler.

  class App extends React.Component {
    render() {
        return (
            <div>
                <h1>Attendees</h1>
                <hr/>
                <Attendees attendees={this.props.attendees} />
            </div>
        )
    }
}

class Attendees extends React.Component {

    render() {
        return (
            <ul className="attendees">
                {this.props.attendees.map((attendee, index) =>
                    <li className="attendees__attendee" key={index}>
                        <Badge attendee={attendee} />
                    </li>
                )}
            </ul>
        )
    }
}


See the Pen 4/7 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

Adding attendees

We've got our badges displaying nicely and outputting our attendees. Now we want to add the functionality so that we can add more attendees.

We need to create a form which will take the attendees name and favourite colour. Then we'll need to send the data off somewhere so we can store it in our stores state. Lets create a AddAttendee component.

Component

The AddAttendee component HTML will make up a form with some basic Foundation classes for styling.

  class AddAttendee extends React.Component {
    render() {
        return (
            <div className="row">
                <div className="medium-6 medium-offset-3 columns">
                    <form ref="addAttendee">
                        <label for="name">Name</label>
                        <input id="name" type="text" ref="name" placeholder="John Doe" />
                        <label for="color">Favourite color</label>
                        <input id="color" type="text" ref="color" placeholder="#2e2e2e" />
                        <button type="submit" className="button">Add attendee</button>
                    </form>
                </div>
            </div>
        )
    }
}

As you can see, it's mainly just a basic HTML form. One thing to note is that we have added ref="" attributes to the inputs and form. This is because we need a way to access those elements when the form submits.

Lets add an onSubmit event handler to our form and bind it with the forms context.

<form ref="addAttendee" onSubmit={this.handleSubmit.bind(this)}>

When the form submits it will now call handleSubmit(). Using the ref's we can grab the values from our two inputs.

  handleSubmit(e) {
    // Stop page refreshing
    e.preventDefault();

        // Store reference to our form references
    let refs = this.refs;

    // Users name
    let name = refs.name.value;

    // Users favourite colour
    let color = refs.color.value

    // Trigger action
    this.props.addAttendee(name, color);

    // Reset form so our inputs are empty again
    refs.addAttendee.reset();
}

Note the line this.props.addAttendee(name, color);. This is where we a calling an action. The Actions name could be anything. We haven't created this action yet so we'll need to do that now.

Actions

When we setup Redux earlier we created a empty Actions object const actions = {}. Our onSubmit handler is calling addAttendee() so lets add it. We can add as many Actions as we like here.

  const actions = {
    addAttendee: (name, color) => {
        return {
            // String for Reducer to pick up
            type: 'ADD_ATTENDEE',
            // Randomly generated id
            id: uuid.v4(),
            // Name and colour we sent through from the form
            name,
            color
        }
    }
};

What's important here is the type: 'ADD_ATTENDEE. This is just a string value. It can be called whatever you want it to be. It should just describe what it's doing. The Reducers will be listening for Actions. Lets create a Reducer that will store our new attendee's name and favourite colour when the addAttendee action has been called.

Reducer

Our Reducer is going to be a switch statement. Here we have access to the applications state and the action being sent to it. The switch statement is passed the action.type which was this type: 'ADD_ATTENDEE' line that we put in the Actions. If the action.type does not match anything we just return the default state.

Inside of the case 'ADD_ATTENDEE': we return a new array. We store our new attendee's details in a object. We also do ..state which concatenates our old state into our new array. It's important in Redux that data is immutable, meaning you should always create and return a new version of the state, instead of modifying the exisiting state.

  function reducer(state = [], action) {
    switch (action.type) {
        case 'ADD_ATTENDEE':
            // Return a new array with old state and added attendee.
            return [{
                    name: action.name,
                    color: action.color
                },
                ...state
            ];
        default:
            return state;
    }
};

Go ahead and enter your name and favourite colour into demo and see it pop up as a badge.

See the Pen 5/10 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

Removing attendees

We now have a fully functioning React Redux Application. Let's extend this further by adding the functionality to remove someone.

Component

Lets create a RemoveAttendee component. We attach a handleOnClick() event to the button. When the function runs it will call the action removeAttendee(index) with the index of the attendee we want to remove.

  class RemoveAttendee extends React.Component {
    handleOnClick() {
        let index = this.props.index;

        this.props.removeAttendee(index);
    }
    render() {
        return (

            <button className="alert button tiny" onClick={this.handleOnClick.bind(this)}> &times; Remove attendee</button>
        )
    }
}

We will add the RemoveAttendee component to the Attendee's component list. So when every attendee badge is rendered out, it will also render a remove button. We'll also pass through the index of the attendee and the removeAttendee action.

  <ul className="attendees">
   {this.props.attendees.map((attendee, index) =>
       <li className="attendees__attendee" key={index}>
           <Badge attendee={attendee} />                                                        <RemoveAttendee removeAttendee={this.props.removeAttendee} index={index} />
       </li>
   )}
</ul>  

Actions

The Actions setup will be very similar to the addAttendee action. We'll add the removeAttendee() function with the correct type and the index data to pass along.

  removeAttendee: (index) => {
    return {
        type: 'REMOVE_ATTENDEE',
        index
    }
}

Reducer

We will set up another case statement in the Reducer called 'REMOVE_ATTENDEE'. We are returning a new version of the state, excluding the one we wanted to delete from the previous state.

  case 'REMOVE_ATTENDEE':
  return [
      // In the array grab the state from beginning to index of one to delete
      ...state.slice(0, action.index),
      // Grab state from the one after one we want to delete
      ...state.slice(action.index + 1)
  ];

Go ahead try removing someone from the list.

See the Pen 6/10 Building your first React Redux App by Allan Pope (@allanpope) on CodePen.

Conclusion

That was a lot, if you made it this far, well done. If I've missed something or got something wrong, please let me know, I'm still learning how React & Redux works. Using React and Redux to build a simple application like this would be overkill, but hopefully this gave you foundation skills to go ahead and start build something more complex.


23,348 7 175