React Beginners Guide | ES6 / Components / State *

+ REACT

ES6ComponentsState

https://medium.com/the-andela-way/a-beginners-guide-to-react-with-es6-a2ed0b5c977e

A Beginner’s Guide to React with ES

Commonly used ES6 Features

Throughout the rest of this book, a number of ES6 features will be used consistently. If you do not have prior experience with ES6 features, this brief introduction will come in handy. If you’re comfortable with ES6 features, skip this section and head to chapter 2 to get started writing your first component.

let and const

let and const are two new keywords that were introduced in ES6 for declaring variables. When used to declare variables, they are scoped to the block and not the function; this means they are only available within that block. Variables declared with let can be re-assigned but cannot be redeclared within the same scope whereas those declared by const must be assigned an initial value but cannot be redeclared within the same scope.

In summary, use let when you plan on re-assigning new values to the variable and const if you’re not planning to re-assign a variable. See an example of using let

let name = 'Edmond';
name = 'Atto';
console.log(name);

//output
Atto
The spread operator

The spread operator denoted by … is used to expand iterable objects into multiple elements as shown in the example below.

const cities = ["Kampala", "Nairobi", "Lagos"];
console.log(...cities);

//output
Kampala Nairobi Lagos

The spread operator can also be used to combine multiple arrays into one array containing all array elements as shown below.

const east = ["Uganda", "Kenya", "Tanzania"];
const west = ["Nigeria", "Cameroon", "Ghana"];

const countries = [...east, ...west];
console.log(countries);

//output
[ 'Uganda', 'Kenya', 'Tanzania', 'Nigeria', 'Cameroon', 'Ghana' ]
Template literals

Before ES6, strings were concatenated using the + operator as shown in the example below.

const student = {
 name: 'John Kagga',
 city: 'Kampala'
};

let message = 'Hello ' + student.name + ' from ' + student.city;
console.log(message);

//output
Hello John Kagga from Kampala

ES6 introduced template literals which are essentially string literals that include embedded expressions. They are denoted by backticks instead of single or double quotes. The template literals can contain placeholders which are represented by ${expression}. The quotes and + operator are dropped when using template literals as shown in the rewrite of the above example below.

let message = `Hello ${student.name} from ${student.city}`;

//output
Hello John Kagga from Kampala
Default function parameters

ES6 introduced a way of adding default values to the function’s parameter list as shown below.

function greet(name = 'Fellow', greeting = 'Welcome') {
 return `${greeting} ${name}`;
}

console.log(greet()); // Welcome Fellow
console.log(greet('Kagga')); // Welcome Kagga
console.log(greet('Mike', 'Hi')); // Hi Mike

A default parameter is created when an equal ( = ) is added and whatever the parameter should default to if an argument is not provided (this parameter) can be any JavaScript data type.

Destructuring

In ES6, data can be extracted from arrays and objects into distinct variables using destructuring. Here are a couple of examples

  1. Extracting data from an array

=> Before ES6

const points = [20, 30, 40];

const x = points[0];
const y = points[1];
const z = points[2];

console.log(x, y, z);//output
20 30 40

=> With ES6

The above example can be changed to use destructuring in ES6 as shown below.

const points = [20, 30, 40];

const [x, y, z] = points;

console.log(x, y, z);//output
20 30 40

The [ ] represent the array being destructured and x, y, z represent the variables where the values from the array are to be stored. You do not have to specify the array indexes because they are automatically implied. During destructing some values can be ignored for example the y value can be ignored as shown below.

const [x, , z] = points

2. Extracting data from an object

=> Before ES6

const car = {
 type: 'Toyota',
 color: 'Silver',
 model: 2007
};

const type = car.type;
const color = car.color;
const model = car.model;

console.log(type, color, model);//output
Toyota Silver 2007

=> With ES6

const car = {
 type: 'Toyota',
 color: 'Silver',
 model: 2007
};

const {type, color, model} = car;

console.log(type, color, model);//output
Toyota Silver 2007

The { } represent the object to be destructed and type, color, model represent the variables where to store the properties from the object. There is no need of specifying the property from where to extract the value from because car already contains a property called type and the value is automatically stored in the type variable.

As with array destructuring, object destructing enables extraction of only the values needed at a given time. The example below shows the extraction of only the color property from the car object.

const {color} = car;
console.log(color);//output
Silver
Object literal Shorthand

ES6 provides a new way of initialising objects without code repetition, making them concise and easy to read. Prior to ES6, objects were initialised using the same property names as the variable names assigned to them as shown below:

let type = 'Toyota';
let color = 'Silver';
let model = 2007;

const car = {
 type: type,
 color: color,
 model: model
};

console.log(car);
//output
{ type: 'Toyota', color: 'Silver', model: 2007 }

Looking closely at the above example, it is clear that type:type, color:color and model:model seem redundant. The good news is that you can remove those duplicate variable names from object properties if the properties have the same name as the variables being assigned to them as shown below.

let type = 'Toyota';
let color = 'Silver';
let model = 2007;

const car = {
 type,
 color,
 model
};
console.log(car);//output
{ type: 'Toyota', color: 'Silver', model: 2007 }
Arrow functions

ES6 introduced a new kind of functions called arrow functions which are very similar to regular functions in behaviour but different syntactically.

As an example, follow the steps below to convert the given regular function into an arrow function.

function (name) { 
  return name.toUpperCase();
}
  • remove the function keyword
  • remove the parentheses
  • remove the opening and closing curly braces
  • remove the return keyword
  • remove the semicolon
  • add an arrow ( => ) between the parameter list and the function body

The result

name => name.toUpperCase();

Using arrow functions
As opposed to regular expressions which can either be function declarations or function expressions, arrow functions are always expressions which can only be used where expressions are valid. Arrow functions can be stored in a variable, passed as an argument to a function or stored in an object’s property.

Parentheses and arrow function parameters
If an arrow function parameter list has one element, there is no need for wrapping that element in parentheses.

name => `Hello ${name}!`

But, if there are two or more items in the parameter list or zero items, the list has to be wrapped in parentheses as shown below.

const hello = () => console.log('Hello React!'); //zero parameters
hello();

const location = (name, city) => console.log(`${name} is from ${city}.`);//two parameterslocation('John', 'kampala');

Block body syntax
When there is need to have more than one line of code in the arrow function body, the block body syntax has to be used. With the block body syntax, curly braces have to be used to wrap the function body and a return statement has to be used to actually return something from the function as shown below.

name => {
  name = name.toUpperCase();
  return `${name.length} characters make up ${name}'s name`;
};

Benefits of using arrow functions
Arrow functions may be preferred because of the following:-

=> short syntax
=> they are easy to write and read
=> they automatically return when their body is a single line of code.

Classes

ES6 introduced classes that are simply a mirage that hides the fact that prototypal inheritance goes on under the hood. These classes are unlike those in class-based languages like Java. Below is an example of an ES6 class.

class Animal {
 constructor(numLegs) {
   this.numLegs = numLegs;
   this.mammal = false;
 }

 isMammal() {
   this.mammal = true;
 }
}

When a new object is constructed from the Animal class, the constructor will run and the variables inside it will be initialised.

Benefits of using classes
With the new class syntax, less code is required to create a function. The function contains a clearly specified constructor function and all the code needed for the class is contained in its declaration.

ES6 also introduced two new keywords, super and extends which are used to extend classes.

Note that classes in javascript are still functions and their behavior is not the same as those in object-oriented programming languages such as Java.

This was a brief, high-level introduction to the ES6 features that will be used throughout the book. It is not meant as a replacement for any fully fledged ES6 resources out there. Refer to this resource to learn more about ES6 features.

https://medium.com/the-andela-way/understanding-react-components-37f841c1f3bb

What are components?

Components are the building blocks of any React app and a typical React app will have many of these. Simply put, a component is a JavaScript class or function that optionally accepts inputs i.e. properties(props) and returns a React element that describes how a section of the UI (User Interface) should appear.

Your first component

const Greeting = () => <h3>Hello World today!</h3>;

This is a functional component (called Greeting) written using ES6’s arrow function syntax that takes no props and returns an h3 tag with the text “Hello World today!”

In Chapter 1, you learnt how to set up a React App using the create-react-app tool. We’ll take a step back momentarily and use a basic setup to learn the basics of components. You can find the starter app here and clone it to your computer.

In order to run the code examples in this chapter on your machine, you first have to install a server globally using nodeJs. Below is the command to install the http-server on your machine. Open your terminal and run:-

npm install http-server -g

Open the index.html file within the Chapter 2/starter-code folder in your text editor and add the Greeting component where you see the instructions to do so. Below is a code snippet of how your index.html file should look like after this change.

Within the starter-code folder run the command below to start the server:-

http-server .

Open the url within the terminal in your browser and you should see the text “Hello World Today!”.

In case you make changes to the code and they are not shown in the browser even after refresh. Try hard refreshing that tab or page.

You did it! You created and rendered your first component. Let’s take a closer look to help us understand what just happened.

Your index.html should look like this at this point



<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Get Started with Vumbula React</title>
</head>

<body>
<div id="root">
    Loading...
</div>
<script src="https://unpkg.com/@babel/standalone/babel.js"></script>
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script type="text/babel">
  // Add your brand new component here
  const Greeting = () => <h1>Hello World today!</h1>;
  ReactDOM.render(
      <Greeting />,
      document.getElementById('root')
  );
</script>
</body>
</html>

=> The React script allows us to write React components

=> The ReactDOM script allows us to place our components and work with them in the context of the DOM

=> The Babel script allows us to transpile ES6 to ES5. Some browsers have limited support for ES6 features; transpiling our ES6 to ES5 allows us to use the modern features of ES6 in our design without having to worry about compatibility. Notice that the React code is wrapped in a script tag with a type of text/babel.

ReactDOM.render(<Greeting />, document.getElementById('root'));

Translating the line of code above to English would sound something like this;

Use ReactDOM’s render method to render the Greeting element into the DOM in a container with the id of root.

When naming a React component, it is convention to capitalize the first letter. This is important because it enables React to differentiate between the native HTML tags such as div, h3, span etc and custom components like Greeting.

A different way to write components

So far, you’ve written a functional component, a fitting name since it really was just a function. Components can also be written using ES6 classes instead of functions. Such components are called class components. Go ahead and convert the functional Greeting component to a class component like so:

class Greeting extends React.Component {
  render(){
    return <h3>Hello World Today!</h3>;
  }
}

Replacing the the functional component in index.html with your new class component and refreshing your browser should also render “Hello World Today!” which means everything is working well.

Functional (Stateless) Vs Class (Stateful) components

By now, you’ve created both a functional and class component. In this section, we’ll take a closer look at the differences as well as situations in which you might prefer to use one type over another.

Functional components

These components are purely presentational and are simply represented by a function that optionally takes props and returns a React element to be rendered to the page.

Generally, it is preferred to use functional components whenever possible because of their predictability and conciseness. Since, they are purely presentational, their output is always the same given the same props.

You may find functional components referred to as stateless, dumb or presentational in other literature. All these names are derived from the simple nature that functional components take on.

=> Functional because they are basically functions

=> Stateless because they do not hold and/or manage state

=> Presentational because all they do is output UI elements

A functional component in it’s simplest form looks something like this:

const Greeting = () => <h3>Hi, I’m a dumb component!</h3>;

Class Components

These components are created using ES6’s class syntax. They have some additional features such as the ability to contain logic (for example methods that handle onClick events), local state (more on this in the next chapter) and other capabilities to be explored in later sections of the book.

As you explore other resources, you might find class components referred to as smart, container or stateful components.

=> Class because they are basically classes

=> Smart because they can contain logic

=> Stateful because they can hold and/or manage local state

=> Container because they usually hold/contain numerous other (mostly functional) components

Class components have a considerably larger amount of markup. Using them excessively and unnecessarily can negatively affect performance as well as code readability, maintainability and testability.

A class component in its simplest form:

class Greeting extends React.Component {
  render(){
    return <h3>Hi, I’m a smart component!</h3>;
  }
}

How do I choose which component type to use?

Use a class component if you:

=> need to manage local state

=> need to add lifecycle methods to your component

=> need to add logic for event handlers

Otherwise, always use a functional component.

As you start out, you will not always know whether to use class or functional components. Many times, you will realise after a while that you chose the wrong type. Do not be discouraged, making this choice gets easier as you create more components. Until then, one helpful tip is, class components that only have markup within the render body can safely be converted to functional components.

Props

In the previous chapter, having reusable components was listed as a benefit of using React, this is true because components can accept props and return a customised React element based on the props received.

Looking at the Greeting component you created earlier, it is clear that it’s not a very useful component to have. In real world situations, you will often need to render components dynamically depending on the situation. You, for example might want the Greeting component to append your application’s current user’s name to the end of the greeting to have output like “Hello Steve” as opposed to having it render “Hello World Today!” every time. Perhaps, you’re always saying hello world, and the world never says hello back.

Props are React’s way of making components easily and dynamically customisable. They provide a way of passing properties/data down from one component to another, typically from a parent to a child component (unidirectional dataflow).

It’s important to note that props are read-only and that a component must never modify the props passed to it. As such, when a component is passed props as input, it should always return the same result for the same input.

All React components should act as pure functions with respect to their props.

Now that you know about props, make use of them in the Greeting component to render a greeting with a custom name appended to it.

Make changes to the code between the script tags in your index.html document to make it look like this:

const Greeting = props => <h3>Hello {props.name}</h3>;
   ReactDOM.render(
     <Greeting name={‘Edmond’}/>,
     document.getElementById('root')
   );

This renders the text “Hello Edmond” to the screen. Go ahead and play around with this by switching out the name for yours.

Using props added some new syntax to your app. Let’s take a closer look and understand what is going on here.

=> An argument (props) is passed to the functional component. Recall that since a single argument is being passed to the arrow function, the parentheses are unnecessary. Passing this argument lets the component know to expect some data to be passed to it (in this case, the name of our app’s user)

=> Within ReactDOM.render, the name you want rendered to the screen is passed in by specifying propName={propValue} within the component’s tag.

=> In the h3 tag, {} are used to print the name that is added to the props object when it’s passed in via the component’s tag. Notice that the name attribute is accessed using the dot syntax.

There is no limit to how many props can be supplied to a component.

Using Props with Class Components

Adding props to class components is a very similar process to the one used in the functional component above. There are two notable changes:

=> Props is not passed as an argument to the class

=> The name attribute is accessed using this.props.name instead of props.name

class Greeting extends React.Component {
     render(){
     return <h3>Hello {this.props.name}</h3>;
     }
   }ReactDOM.render(
     <Greeting name={‘Edmond’}/>,
     document.getElementById('root')
   );

Challenge: Make changes that make it possible for the Greeting component to take name, age and gender props and render this information to the page.

HINT: Pass 3 attributes (name, gender and age) to your component within ReactDOM.render() and alter your h3 text to accommodate your new data. Remember to access the attributes using the right syntax e.g. props.gender for functional components and this.props.gender for class components

Default props

These offer another way to pass props to your component and as the name suggests, default props are used by a component as default attributes in case no props are explicitly passed to the component.

As a fallback, default props are helpful in enabling you offer a better user experience through your app , for example, considering the Greeting component from previous examples, using default props ensures that a complete greeting is always rendered even if the name attribute has not been explicitly passed to the component.


// Greetings Component
const Greeting = props => <h1>Hello {props.name}</h1>;

// Default Props
Greeting.defaultProps = {
  name: "User"
};

ReactDOM.render(
    <Greeting/>,
    document.getElementById('root')
);

By altering the Greeting component as shown above, you now have “Hello User” being rendered in your browser if you do not pass the name attribute to the component.

Passing a name attribute as a prop to the Greeting component overwrites the default props.

Composing Components

Up until now, you’ve only created a single component, however, when building real products, you will often have to build multiple components.

React allows you to reference components within other components, allowing you to add a level(s) of abstraction to your application.

Take for example a user profile component on a social network. We could write this component’s structure like so:

UserProfile
    |-> Avatar
    |-> UserName
    |-> Bio

In this case, UserProfile, Avatar, UserName and Bio are all components. The UserProfile component is composed of the Avatar, UserName and Bio components. This concept of component composition is quite powerful as it enables you to write highly modular and reusable components. For example, the UserName component can be used in many parts of the web application and in case it ever needed to be updated, changes would only be made to the UserName component and the changes would reflect everywhere with the application where it is used.


//Avatar component
const Avatar = () => <img src="http://i.pravatar.cc/300"/>;

//Username component
const UserName = () => <h4>janedoe</h4>;

//Bio component
const Bio = () =>
    <p>
      <strong>Bio: </strong>
      Lorem ipsum dolor sit amet, justo a bibendum phasellus proodio
      ligula, sit
    </p>;

// UserProfile component   
const UserProfile = () =>
    <div>
      <Avatar/>
      <UserName/>
      <Bio/>
    </div>;

ReactDOM.render(
    <UserProfile/>,
    document.getElementById('root')
);

In the code snippet above, the Avatar, UserName and Bio components are defined within the UserProfile component. Try and do this on your own using the index.html file from previous examples.

Functional components can be referenced within class components and vice versa. However, it is not often that you will reference a class component within a functional component; class components typically serve as container components.

Project One

At this point, you have learned enough of the basics. Get your hands dirty by following up with this first project and in case you get blocked, get out the Github repository for this chapter for the solution or leave a comment below in the response area.

Let’s get started

Clone the repository and cd into the chapter 2 folder that contains the code for this chapter. Then fire up a text editor or IDE of your choice, though VSCode or Webstorm are recommended and follow the steps below.

  • Create a project folder to hold the project files.
  • Create an index.html page
  • Create a src folder to hold the JavaScript files.
  • Create an index.js file within the src folder
  • Add a div with an id of root to the body of the index.html.
  • Add the react, react-dom and babel scripts
  • Link to the index.js script below the babel script at the bottom of the html page.
  • Within index.js create a presentational component called Application.
  • Copy all the html within the body of the html template in the starter-code folder within the chapter 2 folder apart from the script tags.
  • Paste this html within the <> </> tags (fragments). We use tags because a React component only accepts one element and all the rest/siblings must be nested within the one parent element.
  • We need to clean up the html code and turn it into JSX that React can understand.
  • Let us start by removing all the html comments like this one <!-— Navbar -→
  • Rename all class instances to className, then close all img tags like so <img className=”card-img-top” src=”img/8.png”/> and also close the horizontal rule <hr/>

class is a reserved name in React, hence, the requirement to change all class instances to className.

  • Copy the img folder and paste it at the root of the project folder.
  • Head back to the index.html file and add the Bootstrap 4 CSS link tag in the head section.
  • Whoop…Whoop…You can now open the html page in the browser and see your new React application.

Here is the code up to this point.

Great work so far, you are moving on well but you are not yet done. You need to break the main component down further into smaller components so that your code is clean and easy to maintain. Let us get back to work.

Into components

Start by creating the Nav component. You can try it on your own and then cross-check your work by reading through the steps below.

  • Below the Application component, create a new functional component with a name Nav.
  • Copy the <nav> </nav> JSX into the Nav component as shown below.

const Nav = () =>
    <nav className="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
      <div className="container">
        <button className="navbar-toggler"
                type="button"
                data-toggle="collapse"
                data-target="#navbarNavAltMarkup"
                aria-controls="navbarNavAltMarkup"
                aria-expanded="false"
                aria-label="Toggle navigation">
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className="collapse navbar-collapse"
             id="navbarNavAltMarkup">
          <div className="navbar-nav">
            <a className="nav-item nav-link"
               href="#home">Home
              <span className="sr-only">(current)</span>
            </a>
          </div>
        </div>
      </div>
    </nav>;


  • Delete the nav code from the Application component JSX and replace it with <Nav/> element as shown here.
  • Open up the application again in the browser and everything should still be the same.
  • Let’s move on to the second presentational component, the Jumbotron.
  • Create an arrow function with a name Jumbotron.
  • Copy the jumbotron code and paste it into the Jumbotron function.
  • Delete the jumbotron code from the Application component’s JSX and replace it with the <Jumbotron/> element.

It is now your turn, go on and create the Toys and Footer functional components and then reference them within the Application component. Be sure to follow similar steps as before.

Nothing about the page in the browser should change after you are done. When you are done cross-check your solution with this.

We have done a good job up to this point, you may have realized that our JSX is not DRY. Meaning there is a lot of repetition specifically in the <Toys/> component, the toy cards are repeated for every toy. We can leverage the power of reusability that React components possess to clean this up.

  • First, create an array called toys to hold objects containing the toy name, description and image number as shown below.


const toys = [
  {
    name: 'Toy One',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '1'
  },
  {
    name: 'Toy Two',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '2'
  },
  {
    name: 'Toy Three',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '3'
  },
  {
    name: 'Toy Four',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '4'
  },
  {
    name: 'Toy Five',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '5'
  },
  {
    name: 'Toy Six',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '6'
  },
  {
    name: 'Toy Seven',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '7'
  },
  {
    name: 'Toy Eight',
    description: `Lorem Ipsum is simply dummy text of the printing
   and typesetting industry. Lorem Ipsum has been
   the industry's standard dummy text ever since the 1500s.`,
    image: '8'
  },
];

  • Create a functional component that accepts props as an argument and name it Card. Copy and paste one card’s JSX code into it from the Toys component as shown below.


const Card = props =>
    <div className="col-md-6 col-lg-3">
      <div className="card mb-3">
        <img className="card-img-top" src={`img/${props.toy.image}.png`}/>
        <div className="card-body">
          <h4 className="card-title text-center">{props.toy.name}</h4>
          <p className="card-text">
            {props.toy.description}
          </p>
        </div>
      </div>
    </div>;

  • We need to make a few changes to the card so that it is reusable by adding placeholders which will be replaced by the actual data to be rendered.
  • The toy name is replaced by {props.toy.name} where toy is a prop object passed into the component from the toys array.
  • The description is replaced by {props.toy.description}.
  • The image src is replaced by a string template literal which accepts {props.toy.image} to make up the image path.
  • Let us make use of our new Card component by refactoring our Toys component. First delete all the cards within a div with a class of row in the Toys component. Then change the function signature to accept props as its only argument.
  • In order to display all the cards again in the Toys component, we make use of the map function to loop through the toys array passed into it as props. This map function accepts a callback function that accepts two arguments, the item in the array and its index. This callback returns a Card component which accepts a toy has its props. React also requires us to add a key to elements that are being looped over so that it can easily keep track of them and the changes applied to them making it easy for it to know what elements to re-render when the underlying data changes. Therefore the index of the toy object within the array acts as the key in this case as shown below.


const Toys = props =>
    <>
      <h1 id="toys"
          className="display-4 my-4 text-center text-muted">Toys
      </h1>
      <div className="row">
        {props.toys.map((toy, index) => <Card key={index} toy={toy}/>)}
      </div>
    </>;

  • Before you can test out the changes there is one more thing to do, otherwise the toys wont show on the page.

We need to pass in the toys array as props to the application component so that the Toys component can get access to them. This is shown in the snippet below.

ReactDOM.render(<Application toys={toys}/>,document.getElementById('root'));

Finally, within the Application component we also need to pass the toys array as props down to the Toys component as shown below. Recall from chapter one that data flow in React is unidirectional.

<Toys toys={this.props.toys}/>

Now open the page again in the browser to view the changes we have made. You will realize that nothing changes in the browser, we still get to see our page design as it was, but now it is fully optimized with React.

At this point you know how components work and how you can make use of them to develop modular React code that represents different sections of your user interface. Here is the final code for this project. The next chapter explains the aspect of state in a React application, do not miss it.

Cleaning up stray points and places where you accidentally clicked with the Type tool can be really helpful. An easy way to clean up your artwork is to choose Object > Path > Clean Up, and select what to clean up (see Figure 10).

 

https://medium.com/the-andela-way/understanding-the-fundamentals-of-state-in-react-79c711be677f

What is State?

State is a JavaScript object that stores a component’s dynamic data and determines the component’s behaviour. Because state is dynamic, it enables a component to keep track of changing information in between renders and for it to be dynamic and interactive.

State can only be used within a class component. If you anticipate that a component will need to manage state, it should be created as a class component and not a functional one.

State is similar to props but unlike props, it is private to a component and is controlled solely by the said component. In the examples from previous chapters, the behaviour of components has primarily depended on the props that are passed down to them. In those cases, the components that receive the props have no control over them because props are read-only.

In Project One from Chapter 2, toys were passed as props to the Application component, and then down to the Toys component. For the Toys component to gain control over the toys data, it should first be converted into a class component and the toys data should be added into state.

It is worth mentioning that state in React is immutable, that is to say, state should never be altered/changed directly but rather, changes should be made to a copy of the current version of the state. This has benefits such as providing the ability to review the state at different points in time and for apps to hot reload (automatic reloading of the page in the browser when you make changes in the code).

Adding State to a Class Component

class Greeting extends React.Component {
  render(){
    return <h3>I’m a component in need of some state!</h3>;
  }
}

Adding state to the Greeting component above involves defining within the class component, a constructor function that assigns the initial state using this.state.

class Greeting extends React.Component {  constructor(props) {
   super(props);
     // Define your state object here
     this.state = {
       name: ‘Jane Doe’
     }
   }   render(){
     return <h3>Hello { this.state.name }</h3>;
   }
}

Notice that the constructor accepts props as an argument, which are then passed to super(). Adding super() is a must when using the constructor.

Passing props is not necessary unless you are making use of them in the component. From the Greeting component above, it’s not necessary to pass props to either the constructor or super(), that is to say, the component can be written like so:

class Greeting extends React.Component {  constructor() {
    super();
    // Define your state object here
  }
  // Define your render method here
}

However, the React docs recommend that you always pass props in order to guarantee compatibility with potential future features

State is accessed using this.state as seen in the Greeting component’s h1 tag.

State is initiated using this.state, however, all subsequent changes to state are made using this.setState. Using this.setState ensures that the components affected by the change in state are re-rendered in the browser.

Investigating State using React Developer tools

One way to accelerate your understanding of React is to make use of the React devtools created by the team at Facebook. The power of React devtools is most apparent when you need to debug your React app by doing a deep dive into the code. The tools enable you to investigate how React is working below the surface when the app is rendered in the browser.

Installing the React Developer tools

The devtools are available for download on both Mozilla Firefox Add-ons and the Chrome Web Store. Follow the appropriate link to install the devtools depending on which browser you have installed on your computer.

Throughout the rest of this book, Chrome will be used as the browser of choice. In order to confirm successful installation of the devtools on Chrome, open the developer tools window using Cmd+Opt+I on a Mac or Ctrl+Alt+I on a windows PC. You should now see a React tab.

Using the React Devtools

With the Greeting component from earlier in this chapter rendered in your browser, open the developer tools and navigate to the React tab. You should see something similar to this

img

img

Mastery of the React DevTools will enable you to gain a better understanding of React’s inner workings and to quickly debug React applications.

Project Three

To better understand the basic use cases of state in React, we shall build a simple application that allows us to create and render records.

What we’ll build

A React app that enables us to keep track of our friends’ names and ages. The app provides a form that we shall use to enter their details. It then renders our friends’ details in beautiful Bootstrap 4 cards.

The finished application looks like this:

img

img

Getting started

Download or clone the projects’ starter files from the repository to your computer so that you can follow along.

In order to run the code examples in this chapter on your machine, you have to first install a server globally using NodeJS. Below is the command to install the http-server on your machine. Open your terminal and run:-

npm install http-server -g

After the installation is done, cd into the Chapter 3 folder then the starter-code folder. Within there run the command below to start the server:-

http-server .

In case you make changes to the code and they are not shown in the browser even after a refresh, try hard refreshing that tab or page.

Below is what will be shown in the browser when you open the localhost url displayed in your terminal.

img

img

Inside src/index.js, there’s a simple class component that renders JSX for a form with name and age fields, and a save button.

Adding state to the component

In order to display the names and ages added to the application, we need to add state to our Application component. We’ll start by adding default state which contains a dummy name and age which will display whenever the page is rendered in the browser.

We do this by initiating state with this.state inside the component’s constructor method like so:

constructor(props) {
  super(props);
  this.state = {
    data: [
      {
        name: ‘John’,
        age: 20
      }
    ]
  }
}

If you are following along, copy and paste the snippet into the Application component just before the render function.

Rendering data from state

To render the state data, a Card presentation component is defined with the functionality to display the name and age from the props passed to it as shown below.

const Card = props =>
  <div className=”col-md-6 col-lg-3">
    <div className=”card mb-3">
      <div className=”card-body”>        <p className=”card-title”>
          <span>Name: </span>{props.info.name}
        </p>        <p className=”card-text”>
          <span>Age: </span>{props.info.age}
        </p>      </div>
   </div>
 </div>;

Add this Card component to the index.js file below the Application component but before the ReactDOM code.

To display the data in state, we need to access the data array using this.state.data and then use JavaScript’s map function to loop through the array so that each of its elements is rendered on the page.

<div className=”row”>
  {
    this.state.data.map(info => <Card info={info}/>)
  }
</div>

The statement containing the Card component is wrapped within a Bootstrap row so that it is displayed within the Bootstrap grid and placed just after the second <hr/> within the class component’s render function.

A card is then displayed in the browser as shown below.

img

img

Checking the console within the developer tools window reveals errors as shown in the screenshot below.

img

img

This means that we need to give each Card element a key so that React can identify each Card and know what to do when changes occur to any one of them. This can easily be fixed using the map function.

The map function accepts a function that accepts two arguments, the array element (info) and its index; this means that we can use the index as a key to the Card component.

Alter the code to match the code within the snippet below.

<div className=”row”>
  {
    this.state.data.map(
      (info, index) => <Card key={index} info={info}/>
    )
  }
</div>

This should clear the error in the console.

Using index as a key in a map function typically works well for small applications whose data is not that dynamic. However, as applications and data sources get larger, using the index as a key becomes unreliable. In these cases, it’s recommended to use a truly unique key, for example an id. In the project above, every object in state can be assigned an id field and this id can then be used as the key like so; key=**{**info.id**}**.

Adding form data to state

The application is incomplete without the functionality to add new names and ages via the form. This requires knowledge of handling user input, a topic that is covered in the next chapter. We’ll stop here for now, and complete building the application in Chapter 4.

Scroll to Top