Creating Jumbles (part 1: structure)

If you are coming here directly and have not yet read the introduction to this series you should go back and do so. However, if you are here on purpose we should, without further ado, carry on with it.

We will be creating an application​ called Jumbles that will allow anyone to create and store complex passwords. All the user has to do is remember a four digit code that will unlock the passwords. “Why?” You ask. Well, creating a To-do App is just so… you know.

How does Jumbles work?

Imagine a 10x10 table on a pice of paper where each cell contains a letter (upper case or lower), number or a symbol; that is what we call a Jumble. Your password is hidden on there and you have a four digit code allowing you to reveal it.

For demonstration purposes lets say you have this Jumble, seen on the picture below, and your pin is 1267. Your password would then start with # and end with Z and contain any character in between. The password would then be:

#<”\Rh462p_Xis.EHecq0@-^Gw3%W#ua)2R42LfCvkyCMJQUuqga^thZ

Note: this App is not intended to be a secure way to store passwords in any way. It is simply fun for me to create.

Now we know what a Jumble is and we can dive right into the creation.


create-react-app

I want to use the simple create-react-app CLI to create my initial app since I don’t have any specific build steps or dependencies that are not supported. If you do you should learn about WebPack and create your own specific build script.

Now, my first step is creating the App by opening a terminal and executing:

create-react-app jumbles

This will create a folder with the name jumbles where the code for my application​ lives. The structure is simple and straight forward:

bjorgvin@computer jumbles $ tree -I 'node_modules'
.
├── README.md
├── node_modules
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
└── yarn.lock

Now we can run the application by executing:

yarn start

We do that within the “jumbles” directory and the command will run the application​ and open a browser showing our bootstrapped application.

Our bootstrapped app rendered in a browser

There are things in the bootstrapped app we don’t need; let’s clean this up. After the clean up we have the following structure:

bjorgvin@computer jumbles $ tree -I 'node_modules'
.
├── README.md
├── node_modules
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.js
│ ├── App.test.js
│ ├── index.js
└── yarn.lock

Our App.js will now look something like this:


Next step in wiring our app is introducing the state management Redux. First we must install redux:

yarn add redux

Now that we have redux installed we create the application state, called store. This is fairly simple if you follow the documentation. I add the following code to index.js before I render the App:

However, there is a new thing there called reducers that does not exist. What is a reducer? Well, a reducer is a simple function like shown here:

A reducer is used to handle specific actions dispatched in the application. I’m not sure of my reducers yet so I simply create a simple reducer, similar to the one above, in a file called reducers.js in the root like expected.


Now that I have my store I need to make it available to my application. Like the documentation states:

The option we recommend is to use a special React Redux component called <Provider> to magically make the store available to all container components in the application without passing it explicitly. You only need to use it once when you render the root component

The Provider component is part of the react-redux module so I must install that first using:

yarn add react-redux

So, I simply wrap my App component with the Provider component like you can see in the updated index.js file:


The store is now available to all container components and we can connect the store using the connect method.

connect

The connect method is full of magic and it provides access to the application state and the dispatch method to a components props. If we were to provide a good accurate description of this method it would become a duplication of the documentation so I ask you to read the documentation.

To put this as simply as possible the connect method will add props to the component it connects. The props it adds will either hold values from the application state or functions that will dispatch actions.

At this time we will use the first kind of prop and provide a prop called welcomeText to our App component that will hold the value of the states welcomeText property. Later we will also be adding actions to the connect method.

What I find wrong with this approach is that now the App component has knowledge of the state structure. A better approach would be letting the reducer provide access to a state it is managing. So if we add a simple method, most commonly known as a selector function, to the reducer that provides the welcome text from the state we end up with a reducer like this

And of course we need to change the connected App component. So we import the method from the reducers and use that method instead of the state directly.

Now, thats better since we can now change the way we structure the state in the reducer without having to worry about the components using it.


Actions

Now that we have the state for our application wired up we need to allow the user some interaction. To keep this simple, for now, we toggle the welcome text when the user clicks it.

We first create actions.js that contains the actions available. An action to toggle the text dispatched when the user clicks the welcome text.

As you can see I have some quirks when it comes to defining the actions. For instance the type object holding the constants of action names. This will, conveniently, allow reducers to reference the types directly instead of counting on magic strings when handling actions.

Well, now that we have the actions we need some way to make them available to the App component so it can dispatch when the user clicks the welcome text. This is easy since there is an argument in the previously used connect method that takes the actions.

What it does is a little bit of magic since it will provide a method as prop to the connected component, namely App, with a name corresponding to the action name. The method will simply dispatch the action using the redux store dispatch action so we don’t have to worry about that part.

We urge you to read the documentation on the redux store and the dispatch action specifically. When encountering magic you should read up on how things are done if you don’t have the magic to help you.

Now we can simply get the action from the props within the App component and we can use that as a normal method when the welcome text is clicked. The full App component will look like this with the user interaction in place.

But, nothing will happen when the user clicks the welcome text since there is currently no one listening. We could let the reducer handle the action and change the state but what if... well, lets not build bridges in hope of rivers on our journey.

To handle the actions for now we change our reducer to manage the state change by referencing the actions like so

Now we will first render the text found in the initial state and when it is clicked it will be toggled between Welcome text 1 and Welcome text 2.


Sagas

We now have an application with a simple interaction but for large application that likes to call a server when an action is made by the user it doesn’t work. So we need a way to dispatch actions that are asynchronous and might call the server (side effects).

This is where sagas come in and to learn more about them there is a nice tutorial you can follow to get a better understanding of the concept. But for our little example we first install the module

yarn add redux-saga

Now we have installed the sagas we need to

Now that we have sagas installed we can create our first sagas by simply create a file called sagas.js and add our saga in there like this

Lets go over this slowly by starting with the default export which yields watchers and each watcher will watch out for a single action. This is a little complex but when you have done a few hundred of them they become very self-explanatory.

For simplicity, and because it is recommended, I name the watchers in the sagas.js file watch* where the * is the action name and the handler for each action is called on* and handles a single action.

What I do in the onToggle handler for the toggle action is flip the text like I did in the reducer but now need some way to provide the new welcome text to anyone willing to handle the new text. This would be the reducer and we need to dispatch a new action carrying the new welcome text.

So we create a new action called toggleResolve indicating the toggle action has been resolved and the result from that action is part of the payload. So lets add that action to the actions.js file.

Now we can dispatch the toggleResolved action when the new welcome text has been created. We have a method, called put provided by the redux-saga/effects, that can help us there. So, lets take a look at the improved sagas.js file

Now that we are dispatching the new toggleResolved action we need someone to handle that action and update the state. We all know who is responsible for managing the application state; yes, the reducers.

When we change the reducer it will no longer handle the toggle action to change the text but simply handle the toggleResolved action and set the new state like this:


Structure

When we start there are few actions, sagas and reducers but when the application starts taking form those will multiply and having everything in a single folder like we do at this point will start to be kind of chaotic. I like to structure my code from the start.

For business logic like toggling the text I like to add a folder called platform and in the case of toggling the welcome text I would have a subfolder inside platform called home and I would copy my sagas.js and actions.js inside this new folder and add a file called reducer.js holding the code currently in the reducers.js file.

My new structure now looks like this

bjorgvin@computer jumbles $ tree -I 'node_modules'
.
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── platform
│ │ ├── home
│ │ │ ├── actions.js
│ │ │ ├── reducer.js
│ │ │ └── sagas.js
│ │ ├── reducers.js
│ │ └── sagas.js
│ ├── App.js
│ ├── App.test.js
│ ├── index.js
│ ├── reducers.js
│ └── sagas.js
└── yarn.lock

Now that we have moved the code to where we think it should be we need to chain together the sagas and the reducers. Take a look at the src/sagas.js and we can see it is only importing the sagas from the platform and yielding like this

Next we look at the imported src/platform/sagas.js since it does not have any sagas itself but only imports sagas from subfolders and yields them like its parent

Now as the application grows we simply add the next subfolder in the platform folder and add the sagas like shown in the comment above with something called next. No other changes are needed to make next available to our application.

The reducers are the same since redux provides a method called combineReducers that allows us to chain them together in much the same way as we did with the sagas. Looking at src/reducers.js we can see this method in action

Next, obviously, we look at the src/platform/reducers.js since it is like the parent not able to provide any reducers of its own. It simply imports the reducers from home and uses the same method as its parent

As you can see it is simple as before and when the application grows you add a subfolder and like shown in the comments add the reducer to the combination method.

There is one thing you need to be aware of and that is the structure of the state. Before we had our getWelcomeText method in src/reducers.js a looking like this

However, when we move the reducer to src/platform/home/reducer.js the part of the state we have access to changed as well so we need to change that to

Like before we should think about when the application grows so will the access to the state. This means we will have more methods like this to access different parts of the state. What I like to do is this

This gives access to my part of the state with an easy select(state) method so if I move my reducer I can simply change the select method and all my other state access methods will work fine.


View

The view is still a simple flat structure and I like to change that so I create a view I call home and add a component there that will render the welcome text. So my new structure looks like this

bjorgvin@computer jumbles $ tree -I 'node_modules'
.
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── platform
│ │ ├── home
│ │ │ ├── actions.js
│ │ │ ├── reducer.js
│ │ │ └── sagas.js
│ │ ├── reducers.js
│ │ └── sagas.js
│ └── view
│ └── home
│ ├── Home.js
│ └── index.js
│ ├── App.js
│ ├── App.test.js
│ ├── index.js
│ ├── reducers.js
│ ├── sagas.js
└── yarn.lock

Now my new App.js is not a connected component and simply renders out the new Home component like this

Like you can see I am importing the folder without specifying any file and what that means is the index.js file is imported. This is where I have my connected Home component so when we look at src/view/home/index.js

You will recognise the file since it simply the connected part of the previous App.js file. The component that renders the welcome text is in src/view/home/Home.js file

Simply render the welcomeText provided through props and also using the toggle action also provided through props.

Now the structure is complete and as the application grows it will be easy to add reducers, actions, sagas and views because of the structure support.


Routes

Next part of the application is allowing our user to navigate the application. However, we only have our one view, home, so there is not much to navigate yet but that will change soon.

First we introduce routs to the mix and have a single route, /home, that will render our home component. We can expand the application by adding more views later.

First we need a module to handle routing and we use React Router. Please visit the documentation from react router to see a quick start and reference for the api.

We are working on an app for the web and that is why we choose the web handler called react-router-dom to install

yarn add react-router-dom

Now we can create our src/routes.js holding our simple Route. I like having my Routes in a specific file since, like with reducers and sagas, I believe routes should be close to their components. So, therefore I export a function that chains together all routes of the application and this will allow the application to grow.

Well, first of you might ask why we have that extra div in there and I would be obliged to tell you that Router does not take multiple children, period.

There is a single variant of the Route component usage where you have a render function and that gives you the power to execute some logic when the user visits a specific path, in this case the root path /. We are, however, only rendering a Redirect when the root path / is visited but you could, for instance, make a decision based on the user context like is done in the documentation about Redirect.

As you can see I import routes from home since I think home should be responsible for its own routes. The src/view/home/routes.js file will look like this

This variant of the Route component has the component property and it simply says if the user visit /home render the Home component.

However, the Router is not yet wired up with the application so we need to head over to the src/index.js file and make some minor wiring.

As you can see there is not much to it; just import our createRoutes method from src/routes.js file and create the routes by calling that method with the history since Routes takes history prop. We are using browser history since we are creating an app for a browser.

What you will notice when you run the application at this point that there is a warning that indicates you are importing src/App.js but not using it; well we don’t really need App any more since our routes are actually rendering the Home component when the user visits the routes /home. We can now go ahead and delete App.js file and the import from src/index.js as well.

Our structure should now be like this

bjorgvin@computer jumbles $ tree -I 'node_modules'
.
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── platform
│ │ ├── home
│ │ │ ├── actions.js
│ │ │ ├── reducer.js
│ │ │ └── sagas.js
│ │ ├── reducers.js
│ │ └── sagas.js
│ └── view
│ └── home
│ ├── Home.js
│ ├── index.js
│ └── routes.js
│ ├── index.js
│ ├── reducers.js
│ ├── routes.js
│ ├── sagas.js
└── yarn.lock

Now we have an application that is ready to grow. All the parts are in place to add views, manage state and interacting asynchronously with a server.

Note: To fetch this part of the code you can fetch the structure branch from GitHub

At this point I thought this article was long enough and decided this needs to be at least a two part article. This is a good place to stop and start working on the next part of the application; wire-framing our views. I will do that in Part 2; lets go…