This app illustrates the working of Redux with React following from Stephen Grider tutorials in Udacity.

The app lists chapters of the Quran with a select button against each chapter. When clicking on each chapter a detail is presented on a panel or card next to it.

The purpose of this app is to illustrate how Redux works with React and provide a boiler plate for other more complex apps.

The entire repo is available in my github, and you can see the finished app here.

install redux and react-redux library

After installed the normal react app, we need two more packages as follows. (I am using yarn, you can use npm as well).

yarn add redux react-redux

Redux will take over the task of handling states and data for us, so we can have our App component as a functional component rather than a class. For this app, we will have two reducers: a) chapter list reducer, and b) selected chapter reducer, and we will have one action creator: select chapter.

Using react-redux we will create two components: Provider and Connect. The provider will get as prop the store of reducers from redux. The hierarcy goes as follows: Provider –> App –> Connect –> ChapterList, ChapterDetail.

The Connect component is a special component that communicates with the Provider through a system other than props (i.e., context system)

structure of files

Here is the structure

/src
  /actions
    index.js (we name it so to reduce the need to name it - just a shortcut)
  /components
    App.js 
    ChapterDetail.js
    ChapterList.js
  /reducers
    index.js
  index.js (will setup both the react and redux stuff)

Here is the src/actions/index.js file:

//Action creator

export const selectChapter = chapter => {
  // return an action
  return {
    type: "CHAPTER_SELECTED",
    payload: chapter
  };
};

and here is the reducer file in src/reducers/index.js. This will hold the data and maintain the state of which chapter is selected.

//static list of chapters

const chapterReducer = () => {
  return [
   {
    "No": 1,
    "name_ar": "الفاتحة",
    "Name": "Al-Fatiha",
    "meaning": "The Opening",
    "no_of_verses": 7,
    "Place": "Meccan",
    "Chronology": 5
  },
  {
      //next chapter and so on
  }
  ];
};

// selecting a surah
const selectedChapterReducer = (selectedChapter = null, action) => {
  if (action.type === "CHAPTER_SELECTED") {
    return action.payload;
  }

  return selectedChapter;
};

The last bit is in the same file (reducers/index.js) hook up the redux bit as follows

import { combineReducers } from "redux";

//static list of chapters

//... same as above....

export default combineReducers({
  chapters: chapterReducer,
  selectedChapter: selectedChapterReducer
});

Finally hookup the provider in the main src/index.js as follows:

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";

import App from "./components/App";
import reducers from "./reducers";

ReactDOM.render(
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,

  document.querySelector("#root")
);

connecting ChapterList.js

Now we need to use the connector to somehow magically hookuo redux with react’s prop system. In order to understand the workings of this connect method which we import from react-redux we need to understand the way it does so in javascript.

To test that run the following snippet in any js playground. Stephen Grider provides on here.

function connect() {
  return function() {
    return "hi there";
  };
}

connect()();

with that in mind here is the connection happening inside our ChapterList component

import React from "react";
import { connect } from "react-redux";

class ChapterList extends React.Component {
  render() {
    return <div>Chapter List</div>;
  }
}

const mapStateToProps = state => {
  console.log(state);
  return state;
};

export default connect(mapStateToProps)(ChapterList);

producing list with Semantic UI

Lets us render a list leveraging on semantic UI classes as follows: (in the ChapterList.js file)

class ChapterList extends React.Component {
  renderList() {
    return this.props.chapters.map(chapter => {
      return (
        <div className="item" key={chapter.title}>
          <div className="right floated cotent">
            <button className="ui button primary">Select</button>
          </div>
          <div className="content">{chapter.title}</div>
        </div>
      );
    });
  }
  render() {
    console.log(this.props);
    return <div className="ui divided list">{this.renderList()}</div>;
  }
}

Also, some elements of styling and class names goes into the App file:

const App = () => {
  return (
    <div className="ui container grid">
      <div className="ui row">
        <div className="column eight wide">
          <ChapterList />
        </div>
      </div>
    </div>
  );
};

Connection and action

Here is the rendering of ChapterList one more time after inserting the action and hooking it up with the connector

import React from "react";
import { connect } from "react-redux";
import { selectChapter } from "../actions";

class ChapterList extends React.Component {
  renderList() {
    return this.props.chapters.map(chapter => {
      return (
        <div className="item" key={chapter.title}>
          <div className="right floated cotent">
            <button
              className="ui button primary"
              onClick={() => this.props.selectChapter(chapter)}
            >
              Select
            </button>
          </div>
          <div className="content">{chapter.title}</div>
        </div>
      );
    });
  }
  render() {
    // console.log(this.props);
    return <div className="ui divided list">{this.renderList()}</div>;
  }
}

const mapStateToProps = state => {
  console.log(state);
  return {
    chapters: state.chapters
  };
};

export default connect(
  mapStateToProps,
  { selectChapter }
)(ChapterList);

That means our connect here makes the react prompt through mapStateToProps have all list of chapters from the reducer file in /reducer/injex.js, and second it will also have a hookup between the onClick chapter and the action defined as selectChapter in the /actions/index.js.

Chapter Detail

Here is the first attempt with the boiler plate.

import React from "react";
import { connect } from "react-redux";

const ChapterDetail = props => {
  console.log(props);
  return <div>Chapter Detail</div>;
};

const mapStateToProps = state => {
  return { chapter: state.selectedChapter };
};

export default connect(mapStateToProps)(ChapterDetail);

Here again the connect brought to the props system the chapter it needs to display, so props.chapter will have all details. What will remain is to display using proper Semantic UI CSS classes, which you can investigate on your own.

Conclusion

Redux makes the management of states very convenient inside react. It has an initial cost of setting up things properly, but then the complexity does not gain over time if you do not mind the initial cost.