Building a Simple React App - Part 4
Tags: react, app
Published: 2020-03-25 11:11:47

---
title: Building a Simple React App - Part 4
published: true
description: This is the final part of the series of articles explaining how to build a simple react app.
tags: react, app
---

In the [previous part](https://kolosek.com/building-simple-react-app-part-3) we connected our application with RESTful API, which made it more realistic. This part is the final part of our series *"How to build simple React app*". On start, we will cover **selectors** and their usage, and then we will go through styling our application, using `.scss`.

## Filtering todos

Next thing we want to enable in our application is filtering todos so that user can see only finished, unfinished or all todos. This can be done with simple filter function bypassing connection between application state and component. For example, we can modify our `TodoListContainer` components `mapStateToProps` to look like this.

```javascript

const getVisibleTodos = (visibilityFilter, todos) => {
  switch (visibilityFilter) {
    case FILTER_ALL:
      return todos;
    case FILTER_DONE:
      return todos.filter(todo => todo.done);
    case FILTER_UNDONE:
      return todos.filter(todo => !todo.done);
    default:
      return todos;
  }
}

const mapStateToProps = state => ({
  todos: getVisibleTodos(state.todoReducer.filter, state.todoReducer.todos)
});
```

This will filter our todos depending on filter value of our todoReducer. This is asimple and intuitive solution, but it has one problem. It will recalculate todo list each time when the component is re-rendered. That is where **selectors** come in. We will use [reselect](https://github.com/reactjs/reselect#example) library for selectors, you can find many examples and explanations about selectors and how they work on their page. Practically what selectors will do is optimize function calls. When we do this through selectors, function which calculates *"visible todos"* will be called only when some parts of the state (that function is using) gets changed, and not every time component is re-rendered. That may be very useful especially when calculations are expensive. Let's see how does all this look like implemented.

First, we will create a new file for our todo selectors, `todoSelectors.js` and put it inside our `TodoList/reducers/` folder.

```javascript
// src/components/Home/TodoList/reducers/todoSelectors.js

import { createSelector } from 'reselect';
import { FILTER_ALL, FILTER_DONE, FILTER_UNDONE } from '../constants';

export const getVisibilityFilter = (state) => state.todoReducer.filter;
export const getTodos = (state) => state.todoReducer.todos;

export const getVisibleTodos = createSelector(
  [ getVisibilityFilter, getTodos ],
  (visibilityFilter, todos) => {
    switch (visibilityFilter) {
      case FILTER_ALL:
        return todos;
      case FILTER_DONE:
        return todos.filter(todo => todo.done);
      case FILTER_UNDONE:
        return todos.filter(todo => !todo.done);
      default:
        return todos;
    }
  }
);
```

First two functions  (`getVisibilityFilter` and `getTodos`) are simple selectors (plain functions) which only subtract part of the state relevant to our real selector. `getVisibleTodos` is actual selector created with `createSelector` function (got from `reselect` library). `createSelector` will create thr function which gets a state as a parameter, then will put that state through all *"plain selector functions"* we provide as first argument (in array), and then those extracted values will be passed to the second parameter, which is our filtering function. You see how does it work, it creates a wrapper around our *"filter"* function which decides if the actual function should be called or not. It works similar to like `connect` on connecting components with the state (if you remember it won't always send props to the component, but only when relevant parts of application state changes). More on selectors read on their [official page](https://github.com/reactjs/reselect#example).

In order for this to work you have to install `reselect` library.

```bash
npm install --save reselect
```

Let's carry on, for now, we are again getting an error about importing non-existing constant, let's fix that first, we need to add following three constants in our `constants.js`.

```javascript
// src/components/Home/TodoList/constants.js

export const FILTER_ALL = 'ALL';
export const FILTER_DONE = 'DONE';
export const FILTER_UNDONE = 'UNDONE';
```

Ok, now everything works, but we haven't connected this *"selector"* anywhere. We will change our `TodoListContainer` to filter todos before sending them to `TodoList`. We just need to import our selector, and to modify our `mapStateToProps` function a bit.

```javascript
// src/components/Home/TodoList/TodoListContainer.jsx

...
import { getVisibleTodos } from './reducers/todoSelectors';
...

...
const mapStateToProps = state => ({
  todos: getVisibleTodos(state)
});
...
```

And of course we need to add `filter` property to our global state, otherwise, our `getVisibilityFilter` (in `todoSelectors.js`) will always return `undefined`.

```javascript
// src/components/Home/Todos/reducers/todoReducer.js

...
const TodoState = new Record({
  todos: [],
  filter: types.FILTER_ALL
});
...
```

That is it, we now connected everything up. If you change initial state value of filter to, for example, `types.FILTER_DONE` will only see finished todos on screen. That is nice, but we need some kind of public interface to enable users to change the filter. We will do that with the new component.

```javascript
// src/components/Home/TodoList/FilterSelect.jsx

import React from 'react';
import PropTypes from 'prop-types';

import { FILTER_ALL, FILTER_DONE, FILTER_UNDONE } from './constants';


const handleChange = (e, changeFilter) => changeFilter(e.target.value);

const FilterSelect = ({ changeFilter }) => (
  <select onChange={(e) => handleChange(e, changeFilter)}>
    <option value={FILTER_ALL}>No filter</option>
    <option value={FILTER_DONE}>Show finished only</option>
    <option value={FILTER_UNDONE}>Show unfinished only</option>
  </select>
);

FilterSelect.propTypes = {
  changeFilter: PropTypes.func.isRequired
};

export default FilterSelect;
```

It is a pretty simple component, just one select with thr binded `onChange` event to a `handleChange` function which calls `changeFilter` action (received through props) with thr value given from option tag. Now just render it somewhere on thr screen, for example in `TodoList` after `</ul>` closing tag. Now we have almost everything connected, but still, in our console, we get an error about failing prop-types. Why is that, because our `FilterSelect` needs `changeFilter` function passed as a prop, and we are not sending anything. Ok, let's delegate that more. We will modify `TodoList` to require that function as well and to send it down. After that `TodoList` will look like this.

```javascript
// src/components/Home/TodoList/TodoList.jsx

import React from 'react';
import PropTypes from 'prop-types';

import Todo from './Todo/Todo';
import AddTodo from './AddTodo/AddTodo';
import FilterSelect from './FilterSelect/FilterSelect';


const TodoList = ({ todos, setTodoDone, deleteTodo, addTodo, changeFilter }) => (
  <div className="todos-holder">
    <h1>Todos go here!</h1>
    <AddTodo addTodo={addTodo} />
    <ul className="todo-list">
      {todos.map((todo) => <Todo key={`TODO#ID_${todo.id}`} todo={todo} setDone={setTodoDone} deleteTodo={deleteTodo} />)}
    </ul>
    <FilterSelect changeFilter={changeFilter} />
  </div>
);

TodoList.propTypes = {
  todos: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.number.isRequired,
    task: PropTypes.string.isRequired,
    done: PropTypes.bool.isRequired
  })).isRequired,
  setTodoDone: PropTypes.func.isRequired,
  deleteTodo: PropTypes.func.isRequired,
  addTodo: PropTypes.func.isRequired,
  changeFilter: PropTypes.func.isRequired
};

export default TodoList;
```

Now we get two errors, both prop-type errors, one is for `TodoList` and other for `FilterSelect` component, and both for `changeFilter` function. We need to a create new action and new reducer handler for this.

```javascript
// src/components/Home/TodoList/actions/todoActions.js

...
export const changeFilter = (visibilityFilter) => ({
  type: types.CHANGE_FILTER,
  payload: {
    filter: visibilityFilter
  }
});
```

```javascript
// src/components/Home/TodoList/reducers/todoReducer.js

// new case added to switch
case types.CHANGE_FILTER:
  return state.set('filter', action.payload.filter);
```

Don't forget to insert constant in `constants.js`

```javascript
// src/components/Home/TodoList/constants.js

export const CHANGE_FILTER = 'CHANGE_FILTER';
```

And thr last thing, to add this inside our `TodoListContainer`, just import action from appropriate action file, and add it inside `mapDispatchToProps`. And that is all. Now filtering is enabled.

## Styling application, and enabling .scss

Each web application needs some style. This part is sometimes done by web designers, but still, sometimes, it is for you to do it, so it is good to know at least basics of CSS3, `.scss` and styling HTML. I must state here that **I am not a web designer**, so this styling isn't done by professional in that area, and probably can be styled better, I just wanted to show you some basics in the styling of application, but for real application styling you should, consult real web designer.

### Setup

For styling, we will use `.scss` format, and to do that we need to make it work with `create-react-app` because it is not provided by default. There is this great [article](https://medium.com/@Connorelsea/using-sass-with-create-react-app-7125d6913760) that writes about adding `.scss` and `.sass` into `create-react-app` and we will do pretty much the same method. We will pick the first method (because it is simpler and more generic), described in detail [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-a-css-preprocessor-sass-less-etc).

First of all, we need to add `.scss` preprocessor (the difference between `.sass` and `.scss` are nicely described [here](https://responsivedesign.is/articles/difference-between-sass-and-scss/)), and one more package we will make use of later.

```bash
npm install --save node-sass-chokidar npm-run-all
```

Next thing we need to do is to modify our npm scripts, don't worry if you don't get everything from this part, it is not that important for programming in react, and it is really nicely described on links I provided up, so you can find it when you need it.

```json
"scripts": {
    "build-css": "node-sass-chokidar src/ -o src/",
    "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
    "start-js": "react-scripts start",
    "start": "npm-run-all -p watch-css start-js",
    "build": "npm run build-css && react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
```

What would this do, on `npm start` it will first run `watch-css` and then `start-js` (which is actually our previous `start`), and `watch-css` will compile all `.scss` files into `same-name.css` files, in same directory. So from our components we will still include `.css` files, even though we haven't created them, or they don't exist in given moment. That is it, we now can start writing our stylesheets.

### Styling

First of all, we will use bootstrap (v4 which is in the time this article is written still in alpha phase, and here used version is `4.0.0-alpha.6`), because it provides a lot of things already implemented, so we can use it (with some modifications) to get it up and running fast. To do that, we will modify base HTML template used for our application `public/index.html`. We need to add stylesheet CDN link in the head tag (on the end) and script CDN links to the end of the body tag.

```html
<!-- Bootstrap stylesheet link, end of the <head> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">


<!-- Bootstrap scripts, end of the <body> tag -->
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
```

And that is it, we have included bootstrap into our app, so we can use it freely inside every component. Next thing we want to do is to override current css files into scss. Let's start from top down. First we will create one file just for constants. we will put it inside `src/components/common/styles/variables.scss`.

```scss
/* src/components/common/styles/variables.scss */

$background-lighter: #3a3a3a;
$background-darker: #222222;
$white: #FFFFFF;
$black: #000000;
$white-shadowed: #C9C9C9;
```

That defines all of colors we will use through application, in all other stylesheet files we will include this file, and use those variables. Next is `Root`.

```scss
/* src/components/Root/assets/styles/index.scss */

@import '../../../common/styles/variables.scss';

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background-color: $background-lighter;
}

.dark-input {
  background-color: $background-lighter !important;
  color: $white !important;


  &::-webkit-input-placeholder {
    color: $white-shadowed !important;
  }
  
  &:-moz-placeholder { /* Firefox 18- */
    color: $white-shadowed !important;  
  }
 
  &::-moz-placeholder {  /* Firefox 19+ */
    color: $white-shadowed !important;  
  }
 
  &:-ms-input-placeholder {  
    color: $white-shadowed !important;  
  }
}

.dark-select {
  background-color: $background-lighter !important;
  color: $white !important;

  option {
    color: $white !important;
  }
}
```

We defined very simple style for `body` tag, we used `$background-lighter` variable to define body background color. And we defined two global classes, `.dark-input` and `.dark-select`, which will use somewhere later, they just provide styles for `input` and `select` tags, accordingly. Just make sure that `src/components/Root/Root.jsx` includes `./assets/styles/index.css`. Note again that components are still importing **.css** files and not **.scss** even though we are writing .scss.

Next is `NotFound`, we renamed `not-found.css` into the `index.scss`, and that is it, its content stays the same, only thing that changed is the name, so we need to fix import inside `NotFound.jsx`
```
// from
import './assets/styles/not-found.css';

// to
import './assets/styles/index.css';
```

And we got to `Home`, here we will actually make some changes. First of all, we rename our `Home/assets/styles/home.css` into `Home/assets/styles/index.scss` and replace content with

```scss
/* src/components/Home/assets/styles/index.scss */

@import '../../../common/styles/variables.scss';

.app-header {
  background-color: $background-darker;
  height: 72px;
  padding: 20px;
  color: white;
  text-align: center;
}

.main-content {
  width: 70%;

  margin: 2% auto;
  padding: 5% 10%;
  border-radius: 33px;
  background-color: $background-darker;
  color: $white;

  -webkit-box-shadow: 10px 10px 26px 0px rgba(0,0,0,0.75);
  -moz-box-shadow: 10px 10px 26px 0px rgba(0,0,0,0.75);
  box-shadow: 10px 10px 26px 0px rgba(0,0,0,0.75);
}
```

And accordingly change html structure

```javascript
// rendering html in src/components/Home/Home.jsx

<div>
  <div className="app-header">
    <h2>ToDo App</h2>
  </div>
  <div className="main-content">
    <TodoList />
  </div>
</div>
```

We extracted some stuff we don't need anymore, it is simplified, and more compact now. One note, for `box-shadow` property there is a site, which generates code for it, pretty cool tool, you can find it [here](http://www.cssmatic.com/box-shadow). Now we go into styling `TodoList`. Same as before we create `assets/styles/index.scss` file and import it inside `TodoList` component. Style content is again pretty simple.

```scss
@import '../../../../common/styles/variables.scss';

.todo-list {
  margin: 30px 0;
  list-style-type: none;

  border: 1px dashed;
  padding: 30px;
}
```

And rendering html, pretty similar.

```javascript
// rendering html of `src/components/Home/TodoList/TodoList.jsx

<div>
  <AddTodo addTodo={addTodo} />
  <ul className="todo-list">
    {todos.map((todo) => <Todo key={`TODO#ID_${todo.id}`} todo={todo} setDone={setTodoDone} deleteTodo={deleteTodo} />)}
  </ul>
  <FilterSelect changeFilter={changeFilter} />
</div>
```

Three more components to go. Let's start from `AddTodo`. Here we don't need any special style defined, so we don't define `assets/style/index.scss` (but that would you do in moment when you need some style for that component), we just change a html a bit.

```javascript
// rendering html of `src/compoennts/Home/TodoList/AddTodo/AddTodo.jsx

<div className="form-group row">
  <input 
    className="form-control dark-input"
    type="text"
    onChange={this.changeTaskText}
    onKeyPress={this.handleKeyPress}
    value={this.state.task}
    placeholder="Task text"
  />
  {this.state.task ? <small class="form-text">Press enter to submit todo</small> : null}
</div>
```

Have you noticed that there is no submit button any more? We changed that, for styling purposes, it looks better with input only, but how do we now submit? In `<input>` tag we added `onKeyPress` handler, mapped to a function `this.handleKyePress`, so let's see that function.

```
class AddTodo extends Component {
  ...
  constructor(props) {
    ...
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }
  
  ...
  handleKeyPress(e) {
    if (e.key === 'Enter')
      this.submitTask(e);
  }
  
  ...
}
...
```

Straightforward function, just checks if the pressed key was `enter`, and if it is, it calls `submitTask` function, which, if you remember, was our handler for submit button. Because this can be a little confusing for a user, we added a little note below the input field, which shows only if input field contains text, and guides user how to submit todo. Also, note that here we are using that class we defined inside `Root/assets/styles/index.scss`, `.dark-input`, that was extracted to root, because it isn't something bound for `AddTodo` component, it is just a look of a an input field, we may need it somewhere else in the project, not only here, that is why those classes are extracted. Ok, next is `Todo`, there we need some style.

```scss
/* src/components/Home/TodoList/Todo/assets/styles/index.scss */

@import '../../../../../common/styles/variables.scss';

.todo-holder {
  display: flex;
  flex-direction: row;

  margin: 10px 0;

  border: 1px dashed;
  padding: 15px;

  &.done {
    background-color: $background-lighter;

    .text {
      text-decoration: line-through;
    }
  }

  .text {
    flex: 7;
    text-align: left;
    margin: 0;

    /* Center text verticaly */
    display: flex;
    align-items: center;
  }

  .buttons {
    flex: 3;

    delete-button {
      border: none;
      padding: 0;

      cursor: pointer;
    }

    .done-button {
      border: none;
      padding: 0;

      cursor: pointer;      
    }

    .control-image {
      width: 24px;
    }
  }
}
```

Nothing complicated, let's see html changes

```javascript
// rendering html of src/components/Home/TodoList/Todo/Todo.jsx

<li className={'todo-holder ' + (todo.done ? 'done' : '')}>
  <p className="text">{todo.task}</p>
  <div className="buttons">
    <a className="done-button" onClick={(e) => { e.preventDefault(); setDone(todo, !todo.done) }}>
      {
        todo.done ? 
          <img src={reactivateImg} className="control-image" alt="Reactivate" /> :
          <img src={doneImg} className="control-image" alt="Set Done" />
      }
    </a>&nbsp;
    <a className="delete-button" onClick={(e) => { e.preventDefault(); deleteTodo(todo.id) }}>
      <img src={deleteImg} className="control-image" alt="Delete" />
    </a>
  </div>
</li>
```

First of al, we added `todo-holder` class to each `<li>` element, and removed that inlined style for done tasks into a class. Task text is wrapped inside `text` class, and buttons inside `buttons` class, buttons are changed from `<button>` tag into `<a>` tags with images inside, and in `onClick` handlers are added `e.preventDefault();` on beginning so that link doesn't actually go somewhere (top of the page). And last but not least `FilterSelect`. We haven't added any special styles here either. But html changed a bit.

```javascript
// rendering html of src/components/Home/TodoList/FilterSelect/FilterSelect.jsx

<div className="form-group row">
  <select className="form-control dark-select" onChange={(e) => handleChange(e, changeFilter)}>
    <option value={FILTER_ALL}>No filter</option>
    <option value={FILTER_DONE}>Show finished only</option>
    <option value={FILTER_UNDONE}>Show unfinished only</option>
  </select>
</div>
```

Nothing special we added some bootstrap classes, and `.dark-select` from our global stylesheet (`Root/assets/styles/index.scss`). And that is it!

## Conclusion

With this part, we have finished this series about building react application from grounds up. We have covered most of the main parts you would need while building a real react application. Some parts are covered in more depth then others, that doesn't necessarily mean that they are more important. I encourage you to read through documentation of all libraries that you are using, and to read more articles written on this topic while working, it is very useful, that is why I have linked many things I found useful in the text(s). You can find all of the source code on [GitHub link](https://github.com/acko-kolosek/simple-react-todo-app). That is it, I hope this was helpful.

*Originally published on [Kolosek blog](https://kolosek.com/building-simple-react-app-part-4/).*