Spring boot and React js fullstack application Part 2

Tafadzwa L Nyamukapa
13 min readSep 18, 2020

--

Full stack application Part 2 with Spring boot and React js, with REACT REDUX , JEST Test Runner

This is a continuation of a Part 1 full stack application with Spring boot and React js, with webpack and babel which the git repository can be found here.

Lets go

Before we move on make sure you have folder structure that we ended up with in Part 1 of this series.

- sample-project-root
- frontend
- src
- actions
- components
- reducers
- src
- main
-java
- js
App.js
index.js
- static
main.css
- resources
- templates
index.html
webpack.config.js
package.json
pom.xml

If not make sure you follow Part1 of this series where we setup our Spring Boot RESTful API Server and configured React with Babel and Webpack.

1. House Keeping

Just a quick one i noticed i had forgot to configure babel in Part1 of the series, If you didn't configure babel just quickly follow the following step, if you had already configured it you can skip this step:

1a Babel Configuration

Add a file name .babelrc to the root directory and configure babel:

{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
},
"useBuiltIns": "usage",
"corejs": 3
}
],
"@babel/preset-react"
],
"plugins": ["@babel/plugin-proposal-class-properties"]
}

1b. main.css

For some reason i noticed that if you put your main.css in /src/main/resources/static just like what Spring docs suggests, like we did in the last tutorial Part 1 , Spring wont recognize it unless you put it inside a css folder. Little weird if you ask me :)

  • So just go ahead and update that and put you main.css file in /src/main/resources/static/css/main.css like so.
  • Remember also to update your main index.html in /src/main/resources/templates/index.html to have the correct reference of your main.css file. See code below:
... 
<link type="text/css" href="css/main.css" rel="stylesheet" />
...

1c. React house keeping

React puts some weird puddings and margins on your components which might not be ideal for your designs, so to fix that up just quickly add this magic code to your main.css.

*{
box-sizing: border-box;
margin: 0;
padding: 0;
}

Make sure to restart your server to effect these changes.

  • NB Make sure your server and webpack watch are running by running:
$ mvn spring-boot:run
$ npm run-script watch

2. Lets do some React Staff Now

So in this section we a re going to quickly implement a User Registration Application. Before i waste much of your time lets just jump in :

2a Components

So we are going to divide our UI into three components:

  • Header Section
  • RegisterUser Section , which is basically going to have our input fields and a submit button
  • Users Section, which is going to display a list of our Registered Users

See Image below to have a visual aid of what we are trying to achieve.

Its always good practice to divide your UI into subsection-components whenever you can as this provides clean code that it easy to maintain.

Now that you have a visual understanding of what we are trying to do , it should now be easier for you to follow. Okay Lets write our first Component.

2a i Header

Go to /frontend/src/components and create a folder called layout , this is where all our layouts will seat, in this case the Header.js component. Now create a Header.js component with the the following code:

The code above shows a functional component called Header. We have used a functional component over a class based component because we are not dealing with life-cycle methods in our layout; You probably have noticed that i am importing an icon from material which is a third part dependency so just quickly install material core and icon dependencies as shown below:

$ npm install @material-ui/core
$ npm install @material-ui/icons

Now that you have installed these dependencies your code should be fine. In react you can do inline styling but in this case i have chosen to do it with a variable instead just to keep the code clean and readable. You need to always remember to export your Component so that it will available for use in other components.

You are probably wondering why your Header is not showing yet on your browser. Nothing to worry about remember our App.js file that is referenced as our entry point by webpack.config.js file ?, we need to bring in our components there , but for now lets just finish coding up these components first then will do that , just hang in a bit :)

2a ii RegisterUser

In the components root folder create a class based RegisterUser.js component with the following code:

Unlike a function based component with only a return statement to render to render out jsx code to DOM , a class based component has render method which renders the jsx to the DOM. Okay so lets break this component down:

  • Constructor — You probably have noticed that we have a constructor with states of our form fields. The constructor in a React component is called before the component is mounted, so this is probably the best place to place our states. React also has multiple life cycle methods besides the constructor but they are beyond the scope of this article except for one (componentDidMount)which we shall discuss in the following section . To lean more of life cycle methods you can find them here.
  • Binding — React uses a concept of binding if you want to have access to the parent component. In this case the form in calling the onSubmit method which is using this which (this) belongs to the parent component, hence a need for binding. React has many ways of binding data to the parent , In this case we are going to use only two of the methods:
  1. Binding in constructor onSubmit method,
  2. Binding using arrow functions onChange method. The onChange method will constantly update the state of our fields as we type some staff in the field areas. To read more about binding you can find the information here
  • Props — The onSubmit method is going to be implemented at the root component App.js. To pass a prop up from the child to a parent component we use a prop keyword this.props.addUser(newUser);, we will discuss more about passing props in a bit.
  • The button has className=btn we are going to add the style in the main.css file in the resources folder See code below:
....
....
.container{
padding: 0 1rem;
}
.btn {
display: inline-block;
border: none;
background: #3b3e66;
color: #fff;
padding: 7px 20px;
cursor: pointer;
}
.btn:hover {
background: #666;
}

The container class will be used in the App.js

Install Prop-types

$ npm install --save prop-types
  • PropTypes provide a mechanism to allow type checking in a component. This allows us to define properties that are being passed to a Component. This is a good practice to always define your props as it gives some sense of robustness in your application.

2a iii App.js

Now i think its time to take a look at our App.js component.

Now this is where all the fun staff begins. Lets break this Component:

  • Bringing in Components in render() : First thing you have probably noticed is that we are bringing in (Header, RegisterUser and Users) components that we want to be painted on the DOM by the render function. These components are the three main section components that we defined earlier on that reference image. We will implement the Users component in a bit.
  • Constructor with state — We have defined a users array in state — this is going to be responsible for storing the state of all users that are going to be retrieved from the Backend(Spring RESTful API).
  • Props React has two mechanisms of dealing with props:
  1. It makes use of one-directional data flow (parent-to-child components).

2. However, with a callback function, it’s possible to pass props back from a child to a parent component.

  • RegisterUser prop — The RegisterUser component has an addUser prop which is referencing to this.addUser meaning we have to implement the addUser method in the class. Remember when we passed the addUser prop in RegisterUser component? This where the addUser method is going to be implemented. So in this case the App.js is using a callback function to receive a prop that has being passed from the child-component.
  • Users two props — Passing users state to the child Users component using the users property. RemoverUser prop using a call back mechanism to received prop from a child component.

2a iv Users

Now create a Users component in the components root folder with the following code.

In this Component we want to render the list of users coming from the App.js parent component.

  • Accessing props- To access props passed from the Parent component App.js we use the this.props. keyword, and map function to iterate through the list of data.
  • UserInfo To keep our code clean ,we are going to pass the user information down to a component called UserInfo , which we will create in a bit.
  • Also note how we are passing a user object prop to the UserInfo component.
  • Notice how we are also passing a prop removeUser callback function from the UserInfo component up to the Parent App.js using the this.props keyword. We’ll show you in a bit where the callback is being triggered from in our UserInfo component.

NB (This might be a bit confusing but in here we are just accessing a prop that has been passed from the child UserInfo component , and will pass that state up to the parent App.js using this.props.removeUser where the removeUser callback function will be implemented.)

  • Proptypes — Users component has a array of users prop that was passed from the Parent App.js component.

2a v UserInfo

Now lets create our final component in the root component folder called UserInfo.js wih the following code.

This component is responsible for displaying the user information and remember it is being rendered from the Users component.

  • Material icons Imports- We are bringing in our Icons from material icons we installed earlier on.
  • Dynamic Styling- If you were wondering how you can do dynamic styling this is one of the way you can do it. Here we are styling the main div component in the render method. Here we are changing the background color based on the id of the user.If the id is odd leave the background white.
  • Destructuring props-This is a way of pulling out variable from a prop, this will make it easier to use the prop variables instead of using this.prop key word timeserver we want to access a prop . In this case we are pulling out id from the props. then to access it we would have to use the id variable without this.props.id. You can try to destructure the rest of the properties email,username, etc.
  • Passing argument to a prop — Onclick method is going to be implemented in a removeUser callback function in our parent component App.js. Now to remove a specific user we need to pass a unique id in this case id. Now passing an argument inside a prop requires us to bind the argument thus in this case passing our arguments in this.props.removeUser.bind(this,id ) binding method.

2b CRUD OPERATIONS IN REACT with axios (FINAL)

Now lets finally implement our crud operations in App.js component:

First import axios a package we installed earlier which allows us to easily perform a get,post,put,delete requests.

GET

  • Life-cycle methods — componentDidMount() — is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request in this case GET operation. Here we are accessing our endpoint “/user/all” from the Spring boot RestFul API to get a list of users from our DB. Notice how we are setting the state of the users from our response.data. So each time we say this.state.users we should be able to access the users retrieved from our endpoint.

DELETE

  • removeUser callback — The remove user call back function is implemented here. In this case we are deleting a user with that passed id from our db. Notice how we are updating the UI by using setState method and a spread operator inside the then callback function
.then(
response =>this.setState( //Updating UI
{users: [...this.state.users.filter(
user => user.id !== id
)]}
)
);

The … spread operator copies whatever is in the users state, then we filter all id that is not equal to the one we are deleting.

POST

  • addUser callback — The post method is hitting the “/user/save” method from our Spring boot RESTful api, and then returns that user. We then use the spread operator in the setState method to copy everything in the users state and then append the returned data.

RUNNING

To run the application make sure your backend is running by typing the following commands in your terminal:

mvn spring-boot:run

Then to run the front end application.

npm run-script watch

Then visit http://localhost:8080/

If you see this page then congratulations you have build Full Stack Application with React js being served by Spring boot RESTful API.

  • NB As you have notice if you have a bigger application with many modules it might be difficult to trace the state of your application by manually using one directional data flow or callback functions to manage your state, then implementing something like REDUX or Context API would be more ideal for state management .

Now i wanted to implement REDUX but i have noticed this tutorial has already been to long enough for that. So i will create a final Part 3 using REDUX.

Now lets test:

Instead of running the tests on our browsers lets quickly do it the right programmable way:

3 TESTING JEST and React Testing Library

Install Testing Library

The React Testing Library is a very light-weight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices.

npm install --save-dev @testing-library/react

It is not a test runner hence we need one:

Install Jest Test Runner

Jest is a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. Jest is widely compatible with React projects, supporting features like, snapshots, mocked modules and timers, and jsdom support

npm add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer

Configure babel.config.js

// babel.config.js
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
};

Update package.json scripts with test runner

"scripts": {
"test": "jest"
}

Its a good practice to create a test for every component you create. Now before we proceed make sure you have put your components inside folders, we want to have each component have it own folder and make sure to update your imports. Now inside these components folder you can create sub-folder called test and put your respective test files . It not mandatory to do this but it just give your project a well organised structure. In my case i now have a folder structure that looks like this:

- components
- layouts
Header.js
- __test__
header.test.js
- register-user
RegisterUser.js
- __test__
register-user.test.js
- user-info
UserInfo.js
- __test__
user-info.test.js
- users
Users.js
- __test__
users.test.js

Now lets implement our first test:

3a header.test.js

  • beforeEach and afterEach — This is for context management , every-time we run a test we want to be able to setup and cleanup our DOM after every test.
  • it — The it function is the main entry point of every test in this file.
  • act — Before you make any assertions you need to first paint the DOM with the component you want to test and the act method is used to render the UI unit component.
  • expect — This will run the assertion in this query we are expecting the component to have a text “User Registration” .

Rule of thumb , always mess around with assertions to make sure your test is run as desired. eg change “User Registration” to “User Registrationmmm” and see if your test fails.

3b register-user.test.js

  • Mocking — The RegisterUser takes a addUser callback prop. Jest allows us to mock the function by simulating a callback function using fn.jest() as shown above.
  • Snapshot — Jest let you save “snapshots” of data with toMatchSnapshot / toMatchInlineSnapshot. With these, we can “save” the rendered component output and ensure that a change to it has to be explicitly committed as a change to the snapshot.

3c user-info.test.js

In this test file we are running two tests as demarcated by the two it functions.

  • Mocking and Fetching Data — Jest allow us to mock a fetch Data async call using the mockImplementation call back which will resolve a Promise json response.
  • toMatchInlineSnapshot — We can match the rendered html to a snapshot using the pretty function . Make sure you install the pretty dependency.

3d users.test.js

he User component expects an array of users.

To run test

$ npm test

To update test eg when snapshots dont match and you want to intentionally update : Run test with an update flag

$ npm test -- -u

If you run your tests with npm test and you have an output simliar to this:

> jest PASS  frontend/src/components/user-info/__test__/user-info.test.js
PASS frontend/src/components/layouts/__test__/header.test.js
PASS frontend/src/components/users/__test__/users.test.js
PASS frontend/src/components/register-user/__test__/register-user.test.js
Test Suites: 4 passed, 4 total
Tests: 7 passed, 7 total
Snapshots: 4 passed, 4 total
Time: 3.666 s
Ran all test suites.

You have successfully wrote some unit testing using JEST test runner in React

  • NB As you have noticed if you have a bigger application with many modules it might be difficult to trace the state of your application by manually using one directional data flow or callback functions to manage your state, then implementing something like REDUX or Context API would be more ideal for state management . Now i wanted to implement REDUX but i have noticed this tutorial has already been to long enough. So i will create a final Part 3 using REDUX.
  • If there is anything you feel i should have covered or improve ,Please let me know in the comments section below.

Thank you for taking your time in reading this article.

END !!

Source Code Git repo

The source code of this Part2 can be found on my git repository here Part 1 git repo is here

Pull Requests

I Welcome and i encourage all Pull Requests

Created and Maintained by

License

MIT License

--

--

Tafadzwa L Nyamukapa

Fullstack developer with a huge passion for building software, and explore new technologies. #Springboot #Django #nodejs #flutter #reactjs #laravelphp #express