[Web dev] Beginner’s guide to react/redux —  how to start learning and not be overwhelmed

in technology •  7 years ago  (edited)

Photo by Roman Mager on Unsplash


Disclaimer: This is a beginner’s guide written by a React/Redux beginner.

Learning a new Javascript framework in 2017 can be a daunting task. Say you finally caught up with Angular, but everyone has moved on to this shiny new thing called React. You read a couple of tutorials and can’t wait to configure your new React project. Wait, there’s another article saying that your should use Redux to manage state for your new app. Beginners can all relate to this article. I consider myself an intermediate dev and I still feel this way:

Medium article - How it feels to learn JavaScript in 2016

When I tried to start my React/Redux project, I browse through countless articles about how to structure my file directory: files grouped by type, grouped by components, grouped by domain…etc.


Source: http://gph.is/2k9DFT4


I realized that I had to start somewhere. The aha moment would come later. In the process, I would understand the pros and cons of each approach. It may be followed by a painful refactoring, but it’s going to be a valuable lesson learned. And I was building to learn anyways.


Step 1: Pick an opinionated approach and stick with it


I followed this tutorial.

Medium article - Redux Step by Step: A Simple and Robust Workflow for Real Life Apps

My learning approach was to start coding up my own app by following the author’s thought process. I find the article to be one of the most helpful tutorials out there. It can still be too much for someone starting out in React/Redux so I documented my journey and made it into my own trimmed-down version.


Step 2: Start small


My goal was really simple at the beginning: render a list of articles I’ve been collecting with a news aggregator app. The response from the news database is going be a collection of articles with the following data structure.



Step 3: Pick a boilerplate

I used the boilerplate created by my lovely instructors at Fullstack Academy.(I didn’t catch the React/Redux train there. My cohort is the last one learning AngularJS) I chose this boilerplate because it uses fullstack javascript: React/Redux for the front end and Express/Sequelize/PostgreSQL for the backend. For the purpose of this exercise, I’ve cleaned up the boilerplate a little bit for people without Express/Sequelize/PostgreSQL to follow along. We’ll only be working with React/Redux from now on.

Here’s the Github repo containing the starting point andfinished code for this exercise.

This is the file structure.

    
      src/
        components/
          ListView.js
          ListRow.js
        containers/
          ArticlesIndex.js
        services/
          articles.js
        store/
          articles/
            actions.js
            actionTypes.js
            reducer.js
          index.js
    
  

Before you follow along this tutorial, if terms like action and reducer don’t ring any bell, I highly recommend you read through the core concept in the official Redux documentation or the article I wrote:

Beginner’s guide to react/redux —painting a mental model

Step 4: Start with Redux state

What state does our app have? We’re talking about a simple one-page app with a list of articles. We need to store the list of articles retrieved from the server. If you take a look at the articles.js in src/services/articles, you’ll see an array populated with articles. Since the purpose of this exercise is to get familiar with the data flow of React/Redux architecture, the getAllArticles() function directly returns the articles we need. In the real world, this function is going to be a asynchronous call to some remote API.

Now the question is how to structure our state. The response from server (or in this case, the getAllArticles function) is an array of objects. We can put it in our state.

    
      state = {
        articles: [{
            "id": 314,
            "title": "6 innovative apps utilizing the ethereum network",
            "source": "Investopedia‎",
            "link": "http://www.investopedia.com/news/6-innovative...",
            "date": "1500523200",
            "type": "msm"
          },
          {
            "id": 893,
            "title": "what is plasma and how will it strengthen...",
            "source": "Investopedia‎",
            "link": "http://www.investopedia.com/news/what-plasma-and...",
            "date": "1502856000",
            "type": "msm"
          }]
      }
    
  

But is this the best way to model state? Consider the scenario where to you have to update an article entry, the app is going to iterate through the array to find the news you’re looking for. What if the array size is really big? This approach is not going to be very performant.

If we structure our state with an object, accessing an article becomes a lookup. To render articles, we can store an additional array of ids.

    
      state = {
        articlesById: {
          314: {
            "id": 314,
            "title": "6 innovative apps utilizing the ethereum network",
            "source": "Investopedia‎",
            "link": "http://www.investopedia.com/news/6-innovative...",
            "date": "1500523200",
            "type": "msm"
          },
          893:     {
            "id": 893,
            "title": "what is plasma and how will it strengthen...",
            "source": "Investopedia‎",
            "link": "http://www.investopedia.com/news/what-plasma-and...",
            "date": "1502856000",
            "type": "msm"
          },
          ...
        },
        articlesIdArray: [314, 893, ...]
      }
    
  

Step 5: Implement the data flow for your state from start to finish

How do we update this state? This is where action and reducer come in. Consider this flow chart:

What’s our user interaction? We want to render the list of articles upon page load so it’s not much of an interaction. To do this, we start with componentDidMount in React view. We can dispatch an action to retrieve articles and notify the reducer. The reducer will evaluate the action and update the state. The updated state will trigger the component to render.

Let’s start by defining the type of actions our app has. It’s a simple constant definition for fetching articles. Later on we can always add more definitions, like updating an entry or deleting an entry.

    
      export const ARTICLES_FETCHED = 'articles.ARTICLES_FETCHED'
    
  

Now let’s get to the action. Remember that the response we get from the backend is an array of object, we turn it into an object using the lodash function keyBy.

    
      import { getAllArticles } from '../../services/articles';
      import * as types from './actionTypes';
      export function fetchAllArticles() {
        return dispatch => {
          // in real life,
          // getAllArticles is probably an API call
          const articles = getAllArticles();
          const articlesById = _.keyBy(articles
              .map(article =>
                _.assignIn({ date: article.date.trim() }, article)),
              'id');
          dispatch({type: types.ARTICLES_FETCHED, articlesById})
        }
      }
    
  

The reducer evaluates the plain object containing the type of action and its payload. It then store the data in the state.

    
      import * as types from './actionTypes';
      const initialState = {
        articlesById: undefined,
      }
      export default function reduce(state = initialState, action = {}) {
        switch (action.type) {
          case types.ARTICLES_FETCHED:
            return {
              ...state,
              articlesById: action.articlesById
            };
          default:
            return state;
        }
      }
    
  

Step 6: Render

We are going to connect a container called ArticleIndex to the article state. AritcleIndex is a smart container that can communicate with the Redux store. Inside ArticleIndex, there is a dumb component called ListView, written by Tal Kol, the author of the Redux tutorial I followed. You can checkout the implementation in the components folder.

ListView takes the articlesById, an array of article ids and a render function. It then renders the list of articles.

How do we get articlesById and an array of article ids to view? Here’s a review of Redux core concept. React view is connected to Redux state through the connect function provided by react-redux library.


Here’s the code that does what this diagram describes. At the bottom of it, we map Redux state and dispatch to React props. In componentDidMount, we invoke the loadArticles, which dispatches the fetchAllArticles action. After the state is updated with articles, articlesById is passed to React view by mapStateToProps.

I apologize about the weird html/jsx syntax in the following code. I'm editing with raw html and it doesn't allow html in a code tag.

    
      import './ArticlesIndex.scss'
      import React, { Component } from 'react';
      import autoBind from 'react-autobind';
      import { connect } from 'react-redux';
      import { ListView, ListRow } from '../components';
      import { fetchAllArticles } from '../store/articles/actions';
      class ArticlesIndex extends Component {
        constructor(props) {
          super(props);
          autoBind(this);
        }
        componentDidMount() {
          this.props.loadArticles()
        }
        render() {
          (!this.props.articlesIdArray) return this.renderLoading();
          return (
            ListView
              rowsById={this.props.articlesById}
              rowsIdArray={this.props.articlesIdArray}
              renderRow={this.renderRow}
            /ListView
          )
        }
        renderLoading() {
          return (
            p
              Loading...
          );
        }
        renderRow(articleId, article) {
          return (
            ListRow
              className="row article-item"
              rowId={articleId}
              onClick
              selected>
              div
                {article.title}
                {article.date}
              div
                {article.source}
            /ListRow
          )
        }
      }
      function mapStateToProps(state) {
        return {
          articlesById: state.articles.articlesById,
          articlesIdArray: _.keys(state.articles.articlesById)
        }
      }
      function mapDispatchToProps(dispatch) {
        return {
          loadArticles() {
            dispatch(fetchAllArticles())
          }
        }
      }
      export default connect(mapStateToProps, mapDispatchToProps)(ArticlesIndex)
    
  

And that’s it! We have a list of articles in our browser!


Step 7: Anti-pattern somewhere in the code?

For the sake of learning data flow in React/Redux, we’ve overlooked another Redux concept so far. React component should access Redux state through selectors. Selectors are usually located in reducer.js files. They are pure functions that access Redux state and return some state properties. With selectors in place, if you alter one of your Redux state that affects more than one component, you only need to update the selector.

Here’s our getArticles selector:

    
      export function getArticles(state) {
        // you can perform some calculation here
        // for example sorting and filtering
        const articlesById = state.articles.articlesById;
        const articlesIdArray = _.keys(articlesById)
        return [articlesById, articlesIdArray];
      }
    
  

The mapStateToProps function in ArticleIndex.js becomes:

    
      function mapStateToProps(state) {
        const [articlesById, articlesIdArray] = articlesSelectors
          .getArticles(state);
        return {
          articlesById,
          articlesIdArray
        }
      }
    
  

Bonus: Follow the same thought process and build a filter

With a list of articles, we can add a bunch of different operations. For example, the articles are all news about Ethereum. They are categorized into two type: news from cryptocurrency community and news from mainstream media. After rendering the list of articles, I added a type filter using the same thought process.


Rinse, Repeat, Refactor

Learning React/Redux is like jumping into a rabbit hole, but it has changed me from a skeptic into a believer. I hope this article will jumpstart your learning.

From the initial baby step, my learning project has turned into a news aggregator and trends tracking app!

CryptoCurrent - Google trends meet cryptocurrency

Thanks for reading!

TC

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  
  ·  7 years ago (edited)

@ytienchu Extremely helpful, thanks for sharing! Is that Reactstrap you're using?

Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
https://medium.com/@tctammychu/beginners-guide-to-react-redux-how-to-start-learning-and-not-be-overwhelmed-af04353101e