0% found this document useful (0 votes)
72 views29 pages

This Won'T Trigger A Re-Render:: Updatecheckbox (Checked) (

Another very important concept that you have to understand is how and when React re-renders components. Luckily, this is an easy concept to learn. There are only two things that can trigger a re-render in a React component: a change to the props that the component receives or a change to its internal state. Although the previous section didn't get into the details about how to change the internal state of a component, it did show how to achieve this. Whenever you use a stateful component (i.e.,

Uploaded by

sfsdfsfdf
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views29 pages

This Won'T Trigger A Re-Render:: Updatecheckbox (Checked) (

Another very important concept that you have to understand is how and when React re-renders components. Luckily, this is an easy concept to learn. There are only two things that can trigger a re-render in a React component: a change to the props that the component receives or a change to its internal state. Although the previous section didn't get into the details about how to change the internal state of a component, it did show how to achieve this. Whenever you use a stateful component (i.e.,

Uploaded by

sfsdfsfdf
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 29

Another very important concept that you have to understand is how and when React re-renders components.

Luckily, this is an easy concept to learn. There are only two things that can trigger a re-render in a React
component: a change to the props that the component receives or a change to its internal state.

Although the previous section didn't get into the details about how to change the internal state of a
component, it did show how to achieve this. Whenever you use a stateful component (i.e., a class
component), you can trigger a re-render on it by changing its state through the setState method. What is
important to keep in mind is that you should not change the state field directly. You have to call
the setState method with the new desired state:

// this won't trigger a re-render:

updateCheckbox(checked) {

this.state.acceptedTerms = checked;

// this will trigger a re-render:

this.setState({

acceptedTerms: checked,

});

In other words, you have to treat this.state as if it were immutable.

Note: To achieve a better performance, React does not guarantee that setState()will

update this.state immediately. The library may wait for a better opportunity when there are more things to
update. So, it is not reliable to read this.state right after calling setState(). For more information, check the
official documentation on setState().

Now, when it comes to a stateless component (i.e., a functional component), the only way to trigger a re-
render is to change the props that are passed to it. In the last section, you didn't have the chance to see the
whole context of how a functional component is used nor what props really are. Luckily again, this is another
easy topic to grasp. In React, props are nothing more than the properties (thus its name) passed to a
component.

So, in the UserProfile component defined in the last section, there was only one property being
passed/used: userProfile. In that section, however, there was a missing piece that was responsible for
passing properties (props) to this component. In that case, the missing piece was where and how you use
that component. To do so, you just have to use your component as if it were an HTML element (this is a nice
feature of JSX) as shown here:
import React from 'react';

import UserProfile from './UserProfile';

class App extends () {

constructor(props) {

super(props);

this.state = {

user: {

name: 'Bruno Krebs',

picture: 'https://cdn.auth0.com/blog/profile-picture/bruno-krebs.png',

},

};

render() {

return (

<div>

<UserProfile userProfile={this.state.user} />

</div>

);

}
}

That's it. This is how you define and pass props to a child component. Now, if you change the user in the
parent component (App), this will trigger a re-render in the whole component and, subsequently, it will change
the props being passed to UserProfiletriggering a re-render on it as well.

Note: React will also re-render class components if their props are changed. This is not a particular behavior
of functional components.

What You Will Build with React


All right! With the concepts describe in the last section in mind, you are ready to start developing your first
React application. In the following sections, you will build a simple Q&A (Question & Answer) app that will
allow users to interact with each other asking and answering questions. To make the whole process more
realistic, you will use Node.js and Express to create a rough backend API. Don't worry if you are not familiar
with developing backend apps with Node.js. This is going to be a very straightforward process, and you will
be up and running in no time.

At the end of this tutorial, you will have a React app supported by a Node.js backend that looks like this:
Developing a Backend API with Node.js and Express
Before diving into React, you will quickly build a backend API to support your Q&A app. In this section, you
will use Express alongside with Node.js to create this API. If you don't know what Express is or how it works,
don't worry, you don't need to get into its details now. Express, as stated by its official documentation, is an
unopinionated, minimalist web framework for Node.js. With this library, as you will see here, you can quickly
build apps to run on servers (i.e., backend apps).

So, to get things started, open a terminal in your operating system, move to a directory where you create
your projects, and issue the following commands:

# create a directory for your project

mkdir qa-app

# move into it

cd qa-app

# create a directory for your Express API

mkdir backend

# move into it

cd backend

# use NPM to start the project

npm init -y

The last command will create a file called package.json inside your backend directory. This file will hold the
details (like the dependencies) of your backend API. Then, after these commands, run the following one:

npm i body-parser cors express helmet morgan


This command will install five dependencies in your project:

 body-parser: This is a library that you will use to convert the body of incoming requests into JSON objects.
 cors:This is a library that you will use to configure Express to add headers stating that your API accepts
requests coming from other origins. This is also known as Cross-Origin Resource Sharing (CORS).
 express: This is Express itself.
 helmet: This is a library that helps to secure Express apps with various HTTP headers.
 morgan: This is a library that adds some logging capabilities to your Express app.

Note: As the goal of this article is to help you develop your first React application, the list above contains a
very brief explanation of what each library brings to the table. You can always refer to the official web pages
of these libraries to learn more about their capabilities.

After installing these libraries, you will be able to see that NPM changed your package.json file to include them
in the dependencies property. Also, you will see a new file called package-lock.json. NPM uses this file to make
sure that anyone else using your project (or even yourself in other environments) will always get versions
compatible with those that you are installing now.

Then, the last thing you will need to do is to develop the backend source code. So, create a directory
called src inside your backend directory and create a file called index.jsinside this new directory. In this file, you
can add the following code:

//import dependencies

const express = require('express');

const bodyParser = require('body-parser');

const cors = require('cors');

const helmet = require('helmet');

const morgan = require('morgan');

// define the Express app

const app = express();

// the database

const questions = [];


// enhance your app security with Helmet

app.use(helmet());

// use bodyParser to parse application/json content-type

app.use(bodyParser.json());

// enable all CORS requests

app.use(cors());

// log HTTP requests

app.use(morgan('combined'));

// retrieve all questions

app.get('/', (req, res) => {

const qs = questions.map(q => ({

id: q.id,

title: q.title,

description: q.description,

answers: q.answers.length,

}));
res.send(qs);

});

// get a specific question

app.get('/:id', (req, res) => {

const question = questions.filter(q => (q.id === parseInt(req.params.id)));

if (question.length > 1) return res.status(500).send();

if (question.length === 0) return res.status(404).send();

res.send(question[0]);

});

// insert a new question

app.post('/', (req, res) => {

const {title, description} = req.body;

const newQuestion = {

id: questions.length + 1,

title,

description,

answers: [],

};

questions.push(newQuestion);
res.status(200).send();

});

// insert a new answer to a question

app.post('/answer/:id', (req, res) => {

const {answer} = req.body;

const question = questions.filter(q => (q.id === parseInt(req.params.id)));

if (question.length > 1) return res.status(500).send();

if (question.length === 0) return res.status(404).send();

question[0].answers.push({

answer,

});

res.status(200).send();

});

// start the server

app.listen(8081, () => {

console.log('listening on port 8081');


});

To keep things short, the following list briefly explains how things work in this file (also, be sure to check the
comments in the code above):

 Everything starts with five require statements. These statements load all libraries you installed with NPM.

 After that, you use Express to define a new app ( const app = express(); ).

 Then, you create an array that will act as your database ( const questions = [];). In a real-world app, you
would use a real database like Mongo, PostgreSQL, MySQL, etc.

 Next, you call the use method of your Express app four times. Each one to configure the different libraries
you installed alongside with Express.

 Right after it, you define your first endpoint ( app.get('/', ...);). This endpoint is responsible for sending
the list of questions back to whoever requests it. The only thing to notice here is that instead of sending
the answers as well, this endpoint compiles them together to send just the number of answers that each
question has. You will use this info in your React app.

 After your first endpoint, you define another endpoint. In this case, this new endpoint is responsible for
responding to requests with a single question (now, with all the answers).

 After this endpoint, you define your third endpoint. This time you define an endpoint that will be activated
whenever someone sends a POST HTTP request to your API. The goal here is to take the message sent
in the body of the request to insert a newQuestion in your database.

 Then, you have the last endpoint in your API. This endpoint is responsible for inserting answers into a
specific question. In this case, you use a route parameter called id to identify in which question you must
add the new answer.

 Lastly, you call the listen function in your Express app to run your backend API.

With this file in place, you are good to go. To run your app, just issue the following command:

# from the qa-app/backend directory

node src

Then, to test if everything is really working, open a new terminal and issue the following commands:

# issue an HTTP GET request

curl localhost:8081
# issue a POST request

curl -X POST -H 'Content-Type: application/json' -d '{

"title": "How do I make a sandwich?",

"description": "I am trying very hard, but I do not know how to make a delicious

sandwich. Can someone help me?"

}' localhost:8081

curl -X POST -H 'Content-Type: application/json' -d '{

"title": "What is React?",

"description": "I have been hearing a lot about React. What is it?"

}' localhost:8081

# re-issue the GET request

curl localhost:8081

If you don't know, curl is a command-line interface that lets you issue HTTP requests with ease. In the code
snippet above, you can see that, with just a few key strikes, you can issue different types of HTTP requests,
define what headers (-H) they need, and pass data ( -d) to backends.

The first command will trigger an HTTP GET request that will result in an empty array being printed out ( []).
Then, the second and the third commands will issue POST requests to insert two questions into your API,
and the fourth command will issue another GET request to verify if these questions were properly inserted.

If you manage to get the expected results, leave your server running and move on to the next section.

Developing Applications with React


With your backend API up and running, you are finally ready to start developing your React application. Not
that long ago, developers willing to create apps with React would have a hard time setting up all the tools
needed (e.g., webpack) to scaffold a React application. However (and luckily), the scenario has changed
after Facebook published a tool called Create React App.
With this tool, you can scaffold a new React application with just one command. As such, to create your
React app, open a new terminal and go to the same directory where you created the backend Node.js app
(i.e., from the qa-app directory). From there, issue the following command:

# the npx command was introduced on [email protected]

npx create-react-app frontend

This will make NPM download and run create-react-app in a single command, passing to it frontend as the
desired directory for your new application. The process involved in scaffolding a new application, as you will
see after running the command above, is not that simple. The tool even needs a bunch of seconds (or a
couple of minutes depending on your internet connection) to create the whole thing. However, when this tool
finishes, you can issue the following commands to run your React app:

# move into the new directory

cd frontend

# start your React app

npm start

Note: If you have Yarn installed, the create-react-app tool will use it to bootstrap your project. As such, you will
need to use yarn start or you will have to run npm install before running npm start.

The last command issued above will start a development server that listens on port 3000and will open the
new app in your default web browser.
After seeing your app, you can stop the server by hitting Ctrl + C so you can install a couple dependencies
that you will need in your application. So, back in your terminal and after stopping the server, run the
following command:

npm i react-router react-router-dom

This command will install two libraries to help you handle the navigation in your app. The first one, react-
router, is the main library that enables seamless navigation. The second one, react-router-dom, provides DOM
bindings for React Router.

Note: If you were using React Native to develop an app for mobile devices, you would install react-router-

native instead.

Then, after installing these libraries, you can open your React project in your preferred IDE so you can start
the real work.

Cleaning Up your React App


Well, actually, before start developing your app, you can remove a few files from it and clean up its code a
little bit. For starter, you can remove the ./src/App.test.js file because you won't create automated tests in
this tutorial. Although this is an important topic, you will skip it for now so you can focus on learning React.

Note: After learning about React, you might get interested into learning about how to add automated tests to
your app. A good resource to help you on that matter is the Testing React Applications with Jest blog post.

Besides that, you can also remove two other files as you won't use them: ./src/logo.svgand ./src/App.css.
Then, after removing these files, open the ./src/App.js file and replace its code with this:

import React, { Component } from 'react';

class App extends Component {

render() {

return (

<div>

<p>Work in progress.</p>

</div>

);

}
}

export default App;

You won't really use the new version of your App component as you will soon replace the contents of this file
again. However, to avoid having code that won't compile, it is a good idea to refactor your App component.

Configuring the React Router in Your App


After cleaning things up, you will need to configure React Router in your app. This will be a pretty simple
step, as you will see. However, keep in mind that to master React Router you would need to read at
least one other article that specifically introduces the subject and all its features.

The thing is, React Router is a very complete solution and, in your first React app, you will touch only the tip
of the iceberg. If you do want to learn more about React Router, please, head to the official documentation.

"React Router is a powerful solution that can help you build amazing
applications."

Tweet This

Having that in mind, open the ./src/index.js file and replace its contents with this:

import React from 'react';

import ReactDOM from 'react-dom';

import {BrowserRouter} from 'react-router-dom';

import './index.css';

import App from './App';

import * as serviceWorker from './serviceWorker';

ReactDOM.render(
<BrowserRouter>

<App />

</BrowserRouter>

, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change

// unregister() to register() below. Note this comes with some pitfalls.

// Learn more about service workers: http://bit.ly/CRA-PWA

serviceWorker.unregister();

In the new version of this file, you are just importing BrowserRouter from the react-router-dom library, and
encapsulating your App component inside this router. That's all you need to start using React Router.

Note: If you haven't seen this file before, this is the piece of logic that makes your React app to be rendered.
More specifically, the document.getElementById('root') defines on which HTML element React must render your
app. You can find this root element inside the ./public/index.html file.

Configuring Bootstrap in Your React App


To make your React app more appealing from the User Interface (UI) point of view, you are going to
configure Bootstrap on it. If you don't know Bootstrap, this is an extremely popular library that helps
developers create good-looking, responsive web apps with ease.

There are multiple ways to integrate React and Bootstrap together. However, as the requirements for your
first application will be quite simple and as you won't need any of its interactive components (i.e., you are
just interested into the basic styles that this library provides), you are going to follow the easiest strategy
available. That is, you are simply going to open your ./public/index.html file and update it as follows:

<!DOCTYPE html>

<html lang="en">

<head>

<!-- ... tags above the title stay untouched ... -->

<title>Q&App</title>
<link rel="stylesheet" href="https://bootswatch.com/4/flatly/bootstrap.min.css">

</head>

<!-- ... body definition stays untouched ... -->

</html>

In this case, you are actually doing two things: you are changing the title of your React app to Q&App, and
you are making your app load a variation of Bootstrap called flatly. If you are interested, you can use any
variation available at Bootswatch, or you can also use the default flavor of Bootstrap. However, you will
probably find the variations available on Bootswatch more appealing.

Creating a Navigation Bar in Your React App


Now that you have configured your app to use Bootstrap, you are ready to create your first React
component. In this section, you will create a component called NavBar (which stands for Navigation Bar), and
you will add it to your React app.

To do so, create a new directory called NavBar inside the src directory of your application and insert a new file
called NavBar.js inside it. In this file, input the following code:

import React from 'react';

import {Link} from 'react-router-dom';

function NavBar() {

return (

<nav className="navbar navbar-dark bg-primary fixed-top">

<Link className="navbar-brand" to="/">

Q&App

</Link>

</nav>

);

}
export default NavBar;

As you can see, the navigation bar component that you are creating is a functional component. You can
create it like a stateless (i.e., functional) component because you don't really need to hold any internal state.

Now, to use your new component, you can open your ./src/App.js file and update it as follows:

import React, { Component } from 'react';

import NavBar from './NavBar/NavBar';

class App extends Component {

render() {

return (

<div>

<NavBar/>

<p>Work in progress.</p>

</div>

);

export default App;

Then, if you run your app by issuing npm start from a terminal, you will see the navigation bar at the top of it.
However, what you won't see is the "work in progress" message that your App component contains. The
problem here is that the navigation bar that you created is using a CSS class ( fixed-top) provided by
Bootstrap that makes it fixed to the top. This means that this component is not taking the default vertical
space as it would if it were a normal div element.

To fix this situation, open the ./src/index.css file and add a margin-top rule, as shown here:

body {

/* ... other rules ... */

margin-top: 100px;

/* ... other rules ... */

Now, if you check your app again, you will see your navigation bar and the "work in progress" message.
Creating a Class Component with React
After creating the navigation bar, what you can do next is to create a stateful component (a class
component) to fetch questions from your backend and to show it to your users. To fetch these questions, you
will need the help of another library, Axios. In a few words, Axios is a promise-based HTTP client for the
browser and for Node.js. In this tutorial, you will only use it in the browser (i.e., in your React app).

To install Axios, stop the React development server and issue the following command:

npm i axios

Then, create a new directory called Questions inside src and a new file called Questions.js inside it. In this file,
you can insert the following code:

import React, {Component} from 'react';

import {Link} from 'react-router-dom';

import axios from 'axios';

class Questions extends Component {

constructor(props) {

super(props);

this.state = {

questions: null,

};

async componentDidMount() {

const questions = (await axios.get('http://localhost:8081/')).data;


this.setState({

questions,

});

render() {

return (

<div className="container">

<div className="row">

{this.state.questions === null && <p>Loading questions...</p>}

this.state.questions && this.state.questions.map(question => (

<div key={question.id} className="col-sm-12 col-md-4 col-lg-3">

<Link to={`/question/${question.id}`}>

<div className="card text-white bg-success mb-3">

<div className="card-header">Answers: {question.answers}</div>

<div className="card-body">

<h4 className="card-title">{question.title}</h4>

<p className="card-text">{question.description}</p>

</div>

</div>
</Link>

</div>

))

</div>

</div>

export default Questions;

There are a few important things going on in this file. First, as mentioned before, you are creating a stateful
component that will hold the questions available in your backend API. So, to do it properly, you are starting
your component with the questions property set to null and, when React finishes mounting your component
(which triggers the componentDidMount method), you are issuing a GET request (through the axios.get call) to
your backend. In the meantime between your request and the response from the backend, React renders
your component with a message saying "loading questions..." (it does so because you instructed it to behave
like that by adding this.state.questions === null && before the message).

Note: This component is touching a topic that was not addressed in this article, the Lifecycle of React
Components. In this case, you are just using one of the extension points provided by React,
the componentDidMount method. You don't really need to understand how this works to follow this tutorial but,
after finishing it, make sure you learn about this topic.

Then, whenever Axios gets a response from the backend, you put the data returned inside a constant
called questions, and you update the state of the component ( this.setState) with it. This update, as you already
learned, triggers a re-render and makes React show all the questions retrieved.

Now, in relation to how your questions are shown, you are using a bunch of div elements with CSS classes
provided by Bootstrap to create a nice Card component. If you want to tweak how this card is shown, make
sure to check the docs.

Besides that, note that you are using a component called Link (from react-router-dom) to make this redirect
users to the following path when clicked: /question/${question.id}. In the next section, you will create a
component to show the answers to a question chosen by the user.
So, as you already understand how your component behaves, the next thing you will need to do is to update
the code of your App component to use your new component:

import React, { Component } from 'react';

import NavBar from './NavBar/NavBar';

import Questions from './Questions/Questions';

class App extends Component {

render() {

return (

<div>

<NavBar/>

<Questions/>

</div>

);

export default App;

Then, if you run your app again ( npm start), you will see this nice page:
Routing Users with React Router
With all these features in place, one important step that you have to learn about is how to handle routing in
your React app. In this section, you will learn about this topic while creating a component that shows the
details of the questions available in your backend.

For starters, you can create a new directory called Question (singular now) and a file called Question.js (also
singular) inside it. Then, you can insert the following code into this file:

import React, {Component} from 'react';

import axios from 'axios';

class Question extends Component {

constructor(props) {

super(props);

this.state = {

question: null,

};

async componentDidMount() {

const { match: { params } } = this.props;

const question = (await

axios.get(`http://localhost:8081/${params.questionId}`)).data;

this.setState({

question,

});
}

render() {

const {question} = this.state;

if (question === null) return <p>Loading ...</p>;

return (

<div className="container">

<div className="row">

<div className="jumbotron col-12">

<h1 className="display-3">{question.title}</h1>

<p className="lead">{question.description}</p>

<hr className="my-4" />

<p>Answers:</p>

question.answers.map((answer, idx) => (

<p className="lead" key={idx}>{answer.answer}</p>

))

</div>

</div>

</div>
)

export default Question;

The way this new component works is actually very similar to the way the Questionscomponent works. This is
a stateful component that uses Axios to issue a GET request to the endpoint that retrieves the whole details
of a question, and that updates the page whenever it gets a response back.

Nothing really new here. What is going to be new is the way this component gets rendered.

So, open the App.js file, and replace its contents with this:

import React, { Component } from 'react';

import {Route} from 'react-router-dom';

import NavBar from './NavBar/NavBar';

import Question from './Question/Question';

import Questions from './Questions/Questions';

class App extends Component {

render() {

return (

<div>

<NavBar/>

<Route exact path='/' component={Questions}/>

<Route exact path='/question/:questionId' component={Question}/>


</div>

);

export default App;

In the new version of your App component, you are using two Route elements (provide by react-router-dom) to
tell React when you want the Questions component rendered and when you want the Question component
rendered. More specifically, you are telling React that if your users navigate to / (exact path='/') you want
them to see Questions and, if they navigate to /question/:questionId, you want them to see the details of a
specific question.

Note that the last route defines a parameter called questionId. When you created the Questions (plural)
component, you added a link that uses the id of the question. React Router uses this id to form the link and
then gives it to your Question component (params.questionId). With this id, your component uses Axios to tell the
backend what question exactly is being requested.

If you check your application now, you will be able to see all your questions in the home page, and you will
be able to navigate to a specific question. However, you probably won't see any answer in your new
component because you never added one. For now, to add answers to your questions, you can issue
requests similar to the following one:

curl -X POST -H 'Content-Type: application/json' -d '{

"answer": "Just spread butter on the bread, and that is it."

}' localhost:8081/answer/1

After that, if you reload your app and go to h

You might also like