#100DaysOfCode Day 35: React.Js Components

Richard Russell
Cold Brew Code
Published in
8 min readJul 1, 2020

Hello, World!

Today, I will be doing a deep dive into React.js, especially regarding concepts such as Components, Component Ownership, Prop Validation, Component Interaction, Component Defaults, ES6+ Components (and difference from normal components), and Stateless Components.

Conventional React Component

The conventional way to write a React Component is as the following:

var Hello = React.createClass({
render: function(){
return <div>Hello {this.props.name}</div>;
}
});
ReactDOM.render(
<Hello name="World" />
document.getElementById('container')
);

Keep in mind that conventional does not necessarily mean that the code above represents best practices; the conventional way is what React’s official documentation promotes.

The React.createClass function must be passed in an argument of Object type. This object defines a react component. The render property is the most important property, and therefore is required; it is responsible for parsing the HTML in JavaScript — JSX.

Web applications are only interesting when they are dynamic. React can turn a static web page into a dynamic one by providing a way to pass data around the system using the props object. This means that when you see the following code in JSX:

<h1>My name is {this.props.name}</h1>

We are telling Reac that when the component is being called, the name property alongside its value should be passed along. The value of name can be placed by writing the following:

<Hello name="World" />

The code above will render the Hello component and set the value of this.props.name into "World". This is the basic anatomy of a React Component.

React Components According to W3Schools

In short, React Components, are function that return HTML elements. They are independent and reusable bits of code and serves the same purpose as a JavaScript function, but work in isolation and returns HTML via a render function. There are two types of Components: Class components and Function components.

When creating a React Class component, the component’s name must start with an upper case letter. The component has to include the extends React.Component statement; this statement creates an inheritance to React.Component and gives your component access to React.Component's functions such as the render() method, which returns HTML code.

Here is an example of a Class component called Car:

class Car extends React.Component {
render(){
return <h2>Hi, I am a Car!</h2>
}
}

With the code above, your React application now has a component called Car, which returns a <h2></h2> element. To use this component in your application, you need to call your Component using HTML syntax. Example:

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

That will display the Car component in the “root” element of the document.

Another way to create a Component is by using the Function component. Here is an example of a Function component:

function Car() {
return <h2>Hi, I am also a Car!</h2>;
}

To call your Car component, you can refer to the Car component as normal HTML with an upper case letter:

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

Component Constructor

If there is a constructor() function in your component, this function will be called when the component gets initiated. The constructor function is where you initiate the component’s properties. In React, the component’s properties should be kept in an object called state.

The constructor function is also where you honor the inheritance of the parent component by including the super() statement, which executes the parent component’s constructor function, and your component has access to all the functions of the parent component, React.Component.

Here is a constructor function in the Car component with a color property:

class Car extends React.Component {
constructor(){
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a Car!</h2>
}
}

We can then call the color property in the render() function to the following:

class Car extends React.Component {
constructor(){
super();
this.state = {color: "red"};
}
render(){
return <h2>I am a {this.state.color} Car!</h2>;
}
}

Props

Another way of handling component properties is by using props. Props are like function arguments, and you can send them into the component as attributes. Here is an example:

class Car extends React.Component{
render(){
return <h2>I am a {this.props.color} Car!</h2>;
}
}
ReactDOM.render(<Car color="red" />, document.getElementById('root'));

So, in a way, props is the reverse of the component’s state. When you use your component’s state, you are defining the property of the object in the constructor and calling the property in the render() function of the Component. On the other hand, when you use props, you will not define any property in the contractor, but rather give said property when rendering the Component.

Components in Components

Similar to calling a function inside another function, we can refer to Components inside other components like the following:

class Car extends React.Component {
render(){
return <h2>I am a Car!</h2>
}
}
class Garage extends React.Component {
render(){
return(
<div>
<h1>Who lives in my Garage?</h1>
<Car />
</div>
);
}
}
ReactDOM.render(<Garage />, document.getElementById('root'));

Components in Files

It is a good practice to re-use code by writing components in separate files. To do that, create a new .js file and put the code inside it. Note that the file must start by importing React, and it has to end by exporting the component. Here is an example:

//In a file called App.js
import React from 'react';
import ReactDOM from 'react-dom';
class Car extends React.Component{
render(){
return <h2>Hi, I am a Car!</h2>
}
}
export default Car;

To use the Car component, you can import the file to your application:

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Car from './App.js';
ReactDOM.render(<Car />, document.getElementById('root'));

States & Props

Dynamic apps must pass data around their system. In React, data movement happens mostly among components and external services that provide the original data. Examples are HTTP and localStorage.

Props are immutable, which means they can only be passed from parent components and cannot be changed. This poses a challenge because modern apps do not rely on having all of its states ready on page load. Ajax or Events could happen, and when data returns, someone needs to be responsible for making updates. This is where React states come in.

Upon initializing React, we define an initial state and keep the state in sync with the props. Once the state is updated, the props can then be easily kept in sync.

class Counter extends React.Component({
getInitialState: function(){
return{
counter: 0
};
},
render: function(){
return <div>
<h2>{this.props.name}</h2>
{this.state.counter}
</div>
}
});
ReactDOM.render(<Counter name={'Counter'} />, document.getElementByid('container'));

In the code above, we created a new React Component class called Counter. We then set an initial state of counter, which has a default value of 0. Note that the code snippet above came from a tutorial published in 2016, which explains the difference in code writing style. I will explain the ES6 writing style in the next chapter, so keep reading!

Component Ownership

If a component renders another component, then the renderer is the owner (parent) of the rendered and has control over it. Let’s take a look at an example of Component Ownership (I will write in ES5 first, so that I can explain ES6 in the next chapters):

var CounterDisplay = React.createClass({
render: function(){
return <div>{this.props.counterProp} </div>
}
})
var Counter = React.createClass({
getInitialState: function(){
return{
counter: 0
};
},
render: function(){
//Child component rendered
//React will throw an error if the DOM doesn't have a parent
return <div><h2>{this.props.name}</h2>
<CounterDisplay counterProp={this.state.counter}></CounterDisplay>
</div>;
}
});
ReactDOM.render(<Counter name={'Counter'} />, document.getElementById('container'));

In the code above, the Counter component now renders another Component, CounterDisplay. This means that Counter is responsible for managing and syncing CounterDisplay's props. You can see this in the following code:

<CounterDisplay counterProp={this.state.counter}></CounterDisplay>

Here, we are calling the CounterDisplay component within the Counter component, the owner in this Component interaction. Because Counter is the owner, it is responsible for giving the value of CounterDisplay's props by assigning the state of Counter to counterProp.

This form of React component interaction is known as parent to child, where the parent component flows data to the child component. If, for example, one is planning to create a child component that incremented and decremented an integer managed in a parent component in the form of a state, we use handlers passed into the child component via the parent component as props.

Take a look at the following code:

var CounterDisplay = React.createClass({
render: function(){
//Calls the handler props once events are fired
return <div>
<div> {this.props.counterProp}</div>
<button onClick={this.props.incrementCounter}>Increase</button>
<button onClick={this.props.decrementCounter}>Decrease</button>
</div>
}
})
var Counter = React.createClass({
getInitialState: function(){
return{
counter: 0
};
},
handleIncrement(){
//Update counter state
this.setState({counter: this.state.counter + 1});
},
handleDecrement(){
//Update counter state
this.setState({counter: this.state.counter - 1});
},
render: function(){
//Pass down handlers to CounterDisplay component
return <div>
<h2>{this.props.name}</h2>
<CounterDisplay counterProp={this.state.conter} incrementCounter={this.handleIncrement} decrementCounter={this.hanldeDecrement}></CounterDipslay>
</div>
}
});
ReactDOM.render(
<Counter name={'Counter'}/>
document.getElementById('container')
);

In the code above, we start by creating a CounterDipslay component; this is the “child” component that will be owned by the Counter component. Inside ConuterDisplay, we are setting three handler props: counterProp, which shows the value of the counter, incrementCounter in the form of a button with the writing “Increase”, and decrementCounter in the form of a button with the writing “Decrease”.

Next, we create our parent component, Counter. In our parent component, we declare the counter state with the initial value of zero. Next, we write down our event handlers, hanldeIncrement() and handleDecrement(). These handlers will handle the data flow from the child component to the parent component. Lastly, we render our JSX code by assigning the counter stat to the counterProp props, handleIncrement function to the incrementCounter prop, and hanldeDecrement function to the decrementCounter prop.

The CounterDipslay component has click events. Their handlers are not found anywhere in the component. Rather, the handlers are handled by the parent component, Counter. The handler in turn updates the state using tihs.setState() method and the counter display props get updated without needing the explicit method of updating the display props.

Component Defaults

You can also set a default value for the component using getDefaultProps:

getDefaultProps: function(){
return{
name: 'Counter'
};
},

This is very useful for setting up default values in an app.

Prop Validation

Validation is used to make sure that the data flowing into your component is structured as expected. Here is an example:

var CounterDisplay = React.createClass({
render: function(){
//Calls the handler props once events are fired
return <div>
<div>{this.props.counterProp</div>
<br />
<button onClick={this.props.incrementCounter}>Increase</button>
<button onClick={this.props.decrementCounter}>Decrease</button>
</div>
},
//Setup validation for each props
propTypes: {
//Must be a number
counterProp: React.PropTypes.number.isRequired,
//Must be functions
incrementCounter: React.PropTypes.func.isRequired,
decrementCounter: React.PropTypes.func.isRequired
}
})

Class Component (ES6)

With ES6, we can use classes to create React components. This means that instead of object as argument with properties, we use class members to define behaviour:

class Comment extends React.Component{
//Render method now a class member rather than an object property
render(){
return <h1>{this.props.name}</h1>;
}
}
React.render(<comment name={'Comment'}/>, document.getElementById('container'));

The name of the component is the class name and the class extends React.Component to inherit its funcitonalities.

There are minor changes to the way you have to set initial states when using class Containers:

class Comment extends React.Component{
constructor(props){
super(props);
this.state={
counter: 0
};
}
render(){
return <h1>{this.props.name}</h1>
}
}
React.render(<Comment name={'Comment'}/>, document.getElementById('container'));

The initial state is now set in the class constructor rather than using getInitialState. It is important to always pass the props back the parent class using super(props).

Just as setting initial state is different from Class, default properties and property validation is also different. We treat the methods responsible for performing these actions like static members of the Component class.

//Validation
Comment.propTypes = {
counterProp: React.PropTypes.number.isRequired,
incrementCounter: React.PropTypes.func.isRequired,
decrementCounter: React.PropTypes.func.isRequired
};
//Defaults
Comment.defaultProps = {
name: 'Counter'
}

Stateless Components

When a component has no states, it is inefficient to use a Class to define the component. You can make use of just functions:

function CommentDisplay(props){
return <div>
<div>{props.counterProp}</div>
<br />
<button onClick={props.incrementCounter}>Increase</button>
<button onClick={props.decrementCounter}>Decrease</button>
</div>
}

--

--

Richard Russell
Cold Brew Code

i like to write about code. i also like cold brew coffee.