How to build simple MERN blog app (with Redux), following “natural growth”, step by step guide - part I

Photo by Francesco Gallarotti on Unsplash

Hi,

probably like most novice developers you noticed at some point that a lot of our work with simple SPA applications boils down to handling CRUD (create, read, update, delete) operations. And at the same time, it is a mechanism universal enough to allow us to create a whole range of functionalities with various applications.

Simply put, it can be said that most of the simple applications we use are based on a schema: the user performs an operation that concerns data, the application processes his request and returns the response which is also representing by some form of data (eg JSON). Therefore, learning to communicate with the backend via API is a natural and very important step in the development of any front-end developer.

There are plenty of tutorials on this topic, and there are many that are really great. However, while using them, I noticed a certain difficulty in the way they guide us through the learning process. As a rule, we get knowledge in the form corresponding to the application logic, i.e. individual layers of application are separated from each other and are discussed one by one. As a result, we get a very large portion of information, where we usually have all CRUD operations mixed together, and we see the way they work only at the very end.

I believe that a much more natural and friendly learning process is learning by creating, that is implementing new functionalities one by one. Thanks to this, we have the opportunity to see the entire process of launching a given functionality from start to finish, on each of the application layers and we can understand it better. I believe that following the ‘natural growth’ of an application can help you absorb the presented knowledge more easily, and without understanding the implemented code, we will never be able to develop our skills.

It sounds interesting? Then I invite you to read on!

In this mini-series of articles we will build a simple "blog application" based on a MERN stack (Mongo, Express, React, Node) with the use of Redux. The whole work has been divided into successive milestones, which correspond to subsequent articles and subchapters representing smaller issues.

What does the action plan look like?

  1. Creating a front-end structure of our application based on React
  2. Implementation of a centralized application state management system (Redux)
  3. Launching the server on Node.js and building a simple API on Express.js
  4. Creating a connection to a MongoDB by using Mongoose

Important note: As we work and write code, we will occasionally make mistakes and look for solutions to them. It is not about propagating bad patterns, but about showing common problems that can be encountered during the implementation of a MERN-based application and showing some approaches to deal with them.

Ok, let’s go!

I. Creating a front-end structure of our application based on React

  1. Organizing the structure and content of the application created using create-react-app*

*if someone feels up to it, he can skip this step (and go straight to point 2 of this article) and download an ordered version of the demo application using this repository:

https://github.com/AndKorbiel/simple-mern-blogging-app.git

The end result of this stage is reflected in the branch basic-setup. I invite the rest to read and work together!

The easiest way to start your adventure with creating simple applications on React.js is by using a ‘ready to go‘ client to build a React application — create-react-app (documentation of this project is available here: https://github.com/facebook/create-react-app). So let's move to the folder on the local machine where we want to keep our project files, fire up the console (e.g. Git Bash) and enter this command:

npx create-react-app simple-blogging-mern-app

This will create the skeleton of a simple, demo application and install all dependencies needed to run the application on React.js in the folder whose name we gave as the second parameter of the command (i.e. in our case simple-blogging-mern-app).

Let’s now display the contents of this folder using our favorite code editor. I will work on Visual Studio Code, which gives access to an integrated terminal, which will greatly facilitate work on our project. In the terminal in VS code (or launched from the console, if you do not have such an option in your editor), we can now use the command that will launch the demo application that we have just installed:

npm start

Wow, isn’t that an exciting sight? This is how every adventure of a novice front-end developer begins …;) Ok, let’s get real. Since we have a working app, it’s time to clean it up a bit. Not everything created by create-react-app will be needed in our case. The initial structure of files and folders looks more or less like this:

A bit of this for a start. What can be safely removed? Let’s focus on the src folder as this is will be our main workspace. Let’s remove the files related to the tests (App.test.js and setupTests.js), because this guide will not include creating and running tests (no worries). The logo.svg file will also not be useful to us.

Immediately better! … Apart from the fact that the app crashed. Fortunately, the console (or possibly the compiler in the browser) tells us what is causing the error:

Huh — that’s an error? No, this is just a tip for further cleaning. So let’s move on to editing the App.js file and change its contents by removing a few unnecessary elements so that it looks like this:

Ok, when we worshiped the tradition and said ‘Hello’ to the world, it’s time to finally finish the cleanup and start with a real carte blanche. Let’s delete the entire content of the App.css file (but not the file itself, as we will need it) and get rid of the serviceWorker.js file (we will rather not use the features it offers).

* In newer versions of the application built on create-react-app, the serviceWorker.js file does not exist, but the reportWebVitals file appeared, which we can also remove, because we will not use its functionality.

Now let’s deal with the index.js file. Correct it a bit so that it looks like this:

Beautiful! Nothing can stop us now. This is the perfect moment to finally start building something, but as professional programmers we must remember to save the effect of our work. The create-react-app client was nice enough to initiate a new repository for us, naming it after our project. It’s a pity it doesn’t have the “create a blog app” feature to do all the work for us yet!

With the command ‘ctrl + c’ we can stop the current process in the terminal (or we can start another terminal in the editor) and then run the standard command checking the current status of work in our repository:

git status

I know — nothing revealing: in response to the command, we get a list of deleted and modified files. We add all files without exception to the commit and create the first commit with a short message, writing:

git add .
git commit -m 'Initial commit'

To keep order in the stages of our work (and to prepare a ready-made solution for the lazy guys), we will create a new branch, where the results of our work will be saved:

git checkout -b 'basic-setup'

Ok, from now on, all changes will be made on the next branches, according to one of the main principles of the art of programming, which says that “we do not commit to the master”. Remember — the main branch (default it is named ‘master’) should only contain ready, fully functional code, not the results of our experiments.

2. Creating the basic structure and functionalities of components

Clean up were necessary, but it’s time to start the real fun, which is creating. What will be our goal at this stage?

We want to create an application for publishing and displaying blog entries, so it must have the appropriate user interface (UI). Colloquially speaking, we will now deal with creating views. However, we will not overly focus on the appearance and styling of components in CSS - it's time to abandon the coloring of the frames and focus on real programming!

According to the rules of art, we start work by creating a new branch — I think the name ‘app-layout’ will be perfect to describe this stage of work:

git checkout -b 'app-layout'

While I mentioned that we won’t pay much attention to CSS, we also don’t want our app to look like a nightmare. So let’s install a package that will help us build the view structure, i.e. Bootstrap (in a version developed specifically for React). To do this, let’s type in the console:

npm install react-bootstrap bootstrap

If we previously killed the process that displayed our application in the browser, let’s fire it back so that we can preview the works live. So let’s type in the console again:

npm start

Well, let's get down to sculpting in the code. Let's start with the main screen of our application. If you have already worked with Bootstrap, you know that it is based on a mesh model stretched into rows (horizontal axis) and columns (vertical axis). If someone does not know this system ... then I recommend waiting with learning React until he catches up with the basics of HTML and CSS.

Let’s create a basic grid on which the layout of our application will be based. In the App.js file, let’s enter the following code:

Yes, I know, it looks terrible without any CSS, but we’ll paint the picture in a moment. Now, a brief explanation of this not-so-fine structure:

  • in React.js, unlike pure HTML projects, we should use the installed Bootstrap library by importing individual elements from it, as well as we do at the beginning:
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import 'bootstrap/dist/css/bootstrap.min.css'
  • HTML structure is based on Bootstrap grid in which we currently have two rows (one for the header and the other for entries) and for now two columns with sample content of our entries

At first glance, you can see a certain repetitive layout (the part corresponding to the entry, i.e. the h2 header and the content):

When writing in React, we shouldtry to transform these types of repated code parts into reusable components. So let’s do it. In the src directory, create a new folder, called components, and in it the Blog-post.js file. This file will have the structure corresponding to the code snippet in the App.js file, but it will allow us to apply the reusability principle in practice.

We have created a functional component with a very simple structure, but thanks to this, the structure of the main file of our application will also be significantly simplified, i.e. App.js, which in the part responsible for rendering will look like this:

Always remember to import your newly created component (sometimes the code editor will do it automatically for you). So for this purpose, add the following command in the 1st line of the App.js file:

import BlogPost from './components/Blog-post';

At this stage, our application should look the same as when it was based only on the App.js file — it means that everything is fine but the structure is much clearer.

The problem is that our Blog-post component is still not particularly reactive and only displays static content. For this to change, we should give it the data to be displayed, instead of hard-coding it in the component code. For this purpose, we will use the props attribute (let’s add it to the the Blog-post.js component):

Props will be passed to our component from the parent (App.js), and for this, we just need to update its code (I only paste the part responsible for rendering):

So far, so good. Our reusable component displays the data transferred with props, but we still cannot say that our application is fully reactive. For that to happen, we have to introduce dynamically changing state into our app.

3. Introducing a dynamically changing state

At this stage, we want the Blog-post.js component to remain stateless, so we will introduce the state to the main component of the entire application, which is App.js. So let’s get down to business.

Our main component App.js was created by default as a function component which cannot handle state by itself. We could extend it with this functionality using the State Hook, but let's leave adding Hooks for later. For now, let’s just change the function component to a class component. For this we need to change its structure a bit. This will be basically a cosmetic change and the corrected App.js file will look like this:

The part responsible for displaying the structure (the inside of the App div) has been removed from the above gist so as not to unnecessarily extend the file content and emphasize what has been changed (the structure of a functional component to a class component). So — we do not remove the redirecting part! Ok? Then we go on.

Now let’s add state to our class component. For this we need to initialize the initial state, by default typing it above the rendering function. Our state will take the initial values, which will be plain text (this will help us later check if the state is properly displayed).

So in the App.js file, above the render () function, let’s add the following code:

state = {
newTitle: 'New post title',
newContent: 'There will go my content...'
}

Now we can use the state value in the component rendering part or… pass it as props to another component. For demonstration purposes, we will add a third article by using our component again. We’ll put the code inside a div with the “App” class, just after the two previous BlogPost instances. It will look like this:

<BlogPost
title={this.state.newTitle}
content={this.state.newContent}
/>

As you can see by going to the preview in your browser, adding another blog post made all three articles fit nicely on the page, taking up equal amounts of space. This is no magic, but an advantage of the Bootstrap mesh. (I know our application still doesn’t look very attractive, but we’ll do something about it in a moment. Now let’s turn to state for a while.)

In order for our state to be dynamic, we need to introduce some way of controlling its content. In our case, classic text input works best, so let’s add it to the application code.

To make things easier, we won’t create it as a separate component for now, but let’s put it directly inside the App.js component. We can try to put it next to the list of articles, Bootstrap should make sure that there is a place for it. Just remember to put the input inside the column (BlogPost components render the columns inside their code, so they arrange it so nicely — if you don’t believe it, check it out for yourself!)

So that our eyes don’t hurt from looking at the input, let’s use ready-made Bootstrap forms right away. To do this, we need to import them first, add the following code to the App.js file (e.g. in line 8):

import Form from 'react-bootstrap/Form';

Then we have to declare this element, at the beginning it can be enough simple form:

<Col>
<Form.Group>
<Form.Control type="text" placeholder="Post title..." />
</Form.Group>
</Col>

For the sake of summary, I will now present the entire code of the App.js file because we’ve changed a lot recently. So at the moment it should look like this:

All clear? I hope so, because nothing extraordinary is happening right now, we are just adding more HTML elements to our application.

We need to spend some more time on the form, because now, although we can use it, we won’t do much with it. So now we tie it to the application state and finally get the long-awaited reactive effect.

For this purpose, we need to create a function that will handle the state change for us and associate it with an event specific to the form.

Let’s start with the function itself — under the state declaration and above the render () function, add the following code (i.e. we start at line 16):

handleChange = (event) => {
const value = event.target.value;
this.setState({
newTitle: value
})
}

I hope you are familiar with the arrow functions and will not be particularly surprised by what is happening here. Briefly: we have created an event handling function to which we pass as an argument the event object, which is emitted by the form when the event is triggered (we will go to that in a moment).

Then we get the value from this object assigning it to the variable and use this variable (value) to update the state using React’s setState function. This is not an ideal way to update the state of the application as it does not handle async properly, but at this stage we don’t have to bother with it.

Now we just need to attach our function to the form and for this we update its code:

<Form.Control type="text" placeholder="Post title..." onChange={e => this.handleChange(e)} />

We assigned our function call to the “onChange” event which is commonly used for forms. We pass the object containing information about this event as an argument when calling our function.

Et voila! Check it out for yourself — our application has achieved the long-awaited reactivity.

If we are doing so well, why not create an additional field in the form that will also allow us to handle editing the content of the post? Nothing simpler, after all, we already have a lot of work done, you just need to add a few simple changes.

In most common cases, the content is longer than the title, so let’s add textarea as type for the input this time, also using the solution offered by Bootstrap. Below the previous input (line 48), let’s add the following code:

<Form.Control as="textarea" rows="3" type="text" placeholder="Post content..." onChange={e => this.handleChange(e)} />

Everything is fine, but it’s too early to open the champagne. As you may have noticed by now, reusing our handleChange () function now causes both inputs to overwrite the title portion of state, which is not what we meant. So we need to have some way to find out which input fired the event and we need to add that logic inside the handleChange () function. Because we won’t be writing a separate function for the second input!

I propose the following solution — let’s add the name attribute to the forms, which will be passed along with the event object and which will allow us to identify the input used. So both our inputs will now look like this:

<Form.Control type="text" placeholder="Post title..." name="title" onChange={e => this.handleChange(e)} /><Form.Control as="textarea" rows="3" type="text" placeholder="Post content..." name="content" onChange={e => this.handleChange(e)} />

All that’s left is to update our event handler with one condition and we’ll achieve our goal:

handleChange = (event) => {
const value = event.target.value;
if (event.target.name === 'title') {
this.setState({
newTitle: value
})
} else {
this.setState({
newContent: value
})
}
}

To sum up, I will present the current code status in our main file — App.js. After the recent changes it should look like this:

4. Adding minor improvements, new component and data layer separation

It’s okay now, but it can always get better. I don’t quite like the fact that passing data to props takes up so much space in the part of the code responsible for rendering. Plus, it’s not the best place to hold this type of information, so I think we’ll move this piece of information to state for the sake of better code organization. We will also improve the way we generate a blog post view, which will also benefit in the future.

Keeping static data in state may not be an ideal solution, but at this stage of our application development it will be a good choice. So let’s create a new array inside state in which each blog entry will be a separate object.

In practice it will look like this:

We have created a list of entries as an array of objects so that we can easily iterate through it using the map function and we will be able to easily access the values ​​of an object by referring to their keys. Thanks to this, we can improve the part responsible for rendering posts as follows, replacing the two previous calls to the BlogPost component (lines from 51):

{this.state.blogPosts.map(post => {
return (
<BlogPost title={post.title} content={post.content}></BlogPost>
);
})}
<BlogPost
title={this.state.newTitle}
content={this.state.newContent}
/>

(I showed a fragment with the third BlogPost component call to which we pass our dynamically changing state so that you know exactly which part of the code to change.)

After introducing the above change, it is immediately noticeable that the third call of the BlogPost component, which is supposed to be a preview for the edited post, is outside the iteration, which is somehow inelegant and not very readable. Time to bite the bullet and really improve this part of our app. For this purpose, we will separate a new component responsible for adding new entries.

In the src / components directory, create a new file called Post-form.js and move the form code to it:

Then, in the App.js file, let’s replace this code with a call to our new component by importing it (line 3):

import PostForm from './components/Post-form';

And calling it (verse 62):

<PostForm />

The form shows, but… Ouch! When we try to use it, an error pops up.

What is going on? The error message says that the property handleChange cannot be referenced as undefined, but in practice the point is that we haven’t changed the refrain to call the function which now needs to be passed as props.

We will cover it as follows — first in the Post-Form component, let’s change the reference to our function from this to props (lines from 8):

<Form.Control type="text" placeholder="Post title..." name="title" onChange={e => props.handleChange(e)} /><Form.Control as="textarea" rows="3" type="text" placeholder="Post content..." name="content" onChange={e => props.handleChange(e)} />

Now let’s add props to this component as a function argument (line 4):

export default function PostForm(props) {

And then let’s pass the handleChange function itself as props to the PostForm component by adding the following code in the App.js file (line 62):

<PostForm handleChange={this.handleChange} />

Cool! However, I would also prefer to change the preview of the edited post to separate component. This will allow us to completely separate the part displaying already created posts from the part where we are working on the new post.

For this purpose, let’s modify the code of the Post-form.js component by transferring the code from App.js to it (remembering to change the reference from ‘this ’to ‘props ’— let’s add the following code in the line 12):

<BlogPost
title={props.title}
content={props.content}
/>

Of course, we also have to import the component code (line 3):

import BlogPost from './Blog-post';

And also about adding new props (those that we just specified: title and content) to the call to the PostFrom component in the App.js file (line 62 of the App.js file):

<PostForm handleChange={this.handleChange} title={this.state.newTitle} content={this.state.newContent} />

After introducing the above changes, we can remove the redner of the BlogPost component from the App.js code — that one instance which served as a preview of the values ​​edited in the form. So we remove the code below:

<BlogPost
title={this.state.newTitle}
content={this.state.newContent}
/>

We should achieve the following effect:

It is not bad, although it is still far from ideal. The layout of our application has become a bit more readable, because the new post we are editing is displayed only under the form.

The right column has become the place responsible for editing the entry (we will underline this in a moment using CSS). However, it would be nice to be able to display the new post also on the list, once the work on it will be finished. So let’s work on this functionality now.

For this purpose, we will create a new method within the App.js component that will perform the task we are interested in.

For a new article to appear on the list of blog entries, we have to add it to the blogPosts array in state, or more precisely: we should update this state. So we need to perform such thing:

addNewPost = () => {
const newPost = {
title: this.state.newTitle,
content: this.state.newContent
}
let currentState = this.state.blogPosts;
currentState.push(newPost)
this.setState({
blogPosts: currentState
})
}

What exactly are we doing here? First, we create a newPost variable to which we assign an object with the current state value for newTitle and newContent (content edited in the form). Next, we create a variable currentState to which we assign an object with the current state value for the blogPosts array and add a new element to this array (newPost object) using the push method. And only at this point we update the state of the application, using the previously created variable. Thanks to this, we do not have to worry about mutating the state of the application, which we would definitely not want to do.

Let’s add the above code to the App.js file, below the handleChange() function declaration, son on line 41. Now, of course, we also need to pass our newly created function as additional props to the PostForm component (line 74):

<PostForm handleChange={this.handleChange} title={this.state.newTitle} content={this.state.newContent} addNewPost={this.addNewPost} />

We need to somehow handle this new functionality inside the PostForm.js component. A button will be perfect for this task. So let’s import an element from Bootstrap and add it to the component code, while assigning props to the event that will call the function from the parent component:

The comments that I add in the import part are optional, but I think they will help us not to get confused in distinguishing the imported items, which may be important when the application grows later.

At this stage, I recommend checking the application in practice, and even writing your first blog entry. Remember, if you feel that you have a flair for it, you can always quit learning React and start blogging professionally … But we will miss you!

5. Improving application look and feel

Adding new posts works, but as you can easily see when we refresh the page, the effects of our hard work disappear! It’s a pity, but we can’t do anything about it for now, as the data we have entered is not saved anywhere. We will deal with this functionality in the part dedicated to connecting to the database.

Meanwhile, let’s focus on another problem, which is the visual side of the application. I promised not to devote too much attention to it, but it would be worthwhile to cover this topic at least enough to reveal app basic structure. For example to highlight the division into the list of entries and the part responsible for editing (the form and preview of the new post).

So let’s separate these sections. For this, we need to add some classes to HTML elements and then style them in CSS.

Let’s start with the post editing section. It would be good to emphasize it somehow. I think that simply changing the background color and adding a box shadow will be fine at the beginning. So let’s add a class to main element in Post-Form.js component (line 10):

export default function PostForm(props) {
return (
<Col className="post-form">

Let’s give it the right look by entering the appropriate values ​​in CSS. For ease of use, we will use the global App.css file:

.post-form {
background: #f2f2f2;
padding: 15px;
box-shadow: 2px 2px 2px #a8a8a8;
border-radius: 6px;
}

Of course, we must remember to import this file to the main component (App.js), otherwise the styling will not be visible.

A small change will also take place in the BlogPost component to which we will add one class — it will look like this:

return (
<Col>
<div className="post">
<h2>{props.title}</h2>
<p>{props.content}</p>
</div>
</Col>
)

Ok, a few more changes will be needed, which I will cover briefly but I will not post code for each one separately. It's really a waste of time to focus on appearance when learning to develop React applications. I believe that on this stage it is enough for the appearance of the application not to disturb its readability.

After making few lesser changes, the App.js file will look like this:

Regarding the above changes to the main component:

  • we added a new class representing the header to the row with the title, by the way removing redundant code that accidentally got there (header h2)
  • the part responsible for displaying blog posts has also been redesigned. We placed it entirely in one column, adjacent to the second, smaller column in which the entry editing form was located. This allowed us to provide the form with a fixed width, regardless of the number of entries added
  • by introducing changes in CSS, we will also highlight the list of entries and individual entries, limiting the number of entries in a row to a maximum of four by setting the maximum width (this is in a moment)

Now let’s move on to the changes in the PostForm component:

There are some cosmetic changes to the code above, including the introduction of h3 headings to separate the individual component sections. Although the code has not changed much, I have included it in full to avoid confusion.

As for CSS, it will look like this:

There is nothing special about this code, but it’s about keeping things readable. After making the above changes, our app should now look something like this:

How do you find this shades of gray’ style? In my opinion, it perfectly fits into the canon of minimalist elegance… ;) But seriously speaking— I emphasize once again that the goal of this series of articles is to learn the basics of the MERN stack, therefore we focus primarily on functionality.

However, if you are passionate about graphic design and your suffer from the sight of such a layout, feel free to make any changes! Just don’t forget to share the effect of your improvements in the comments!

If you would find out that something does not work or does not look as it should, you can always refer to the application code from the repository. The final state of this stage of work is reflected in the branch app-layout:

https://github.com/AndKorbiel/simple-mern-blogging-app/tree/app-layout

That’s it for now, in the next chapter we’ll look at adding a Redux (centralized state managing system) to our app. So there will be a lot going on!

Front-end developer, based in Krakow, Poland