This post is a part of the React Daily UI post series, a joint effort between Jack Oliver, Sophia Shoemaker, and the rest of the team at Fullstack React. Each day we're explaining in detail how to create a UI component with React.
You can view the Codepen implementation here
Or you view the code on Github here
Welcome to React Daily UI, where we go 100 days building 100 beautiful React applications. We're really excited to be partnering with Jack Oliver who is embarking on this ambitious project with us.
Jack is designing and writing the code for these applications and we're going to deconstruct each one to highlight the features that are unique to React.
Today we're going to create a profile page:
Overview
This profile page has a few components that are generated using the createClass method available in React. Today we are going to learn how to convert these components into functional and class components. We have three different components that we are going to convert:
- An
Imagecomponent - A
Profilecomponent - An
Appcomponent
We will convert the first two components to functional components and the App component to a class component.
Table of Contents
Functional Components
Functional components are the simplest (and most performant) types of components. They are just a JavaScript function that receive props as a parameter. Functional components do not have state or a this object. When mounted, they receive data from their parent component and display the data.
Functional components are akin to React components that only implement the
render()method. For components that only have a view, functional components are the way to go.
Our profile page has two components that we are going to convert to functional components: the Image component and the Profile component.
Converting the Image component
Our original Image component looks like this:
var Image = React.createClass({
render: function() {
return (
<div className="Image" style={{backgroundImage: 'url(' + this.props.src + ')'}}></div>
);
}
});
To convert our Image component, we are going to do 3 things:
- Create a new function that has the same name as our
Imagecomponent:
function Image(props){
- Take the
returnvalue from ourrendermethod in our original component and make that thereturnvalue of our function.
return (
<div className="Image" style={{backgroundImage: 'url(' + this.props.src + ')'}}></div>
);
- If we have any
propsin our component, we need to remove thethiskeyword, since thepropsare passed in as a parameter to the function. In ourImagecomponent, we changethis.props.srctoprops.src
Here is what our newly created Image component looks like now:
function Image(props){
return (
<div className="Image" style={{backgroundImage: 'url(' + props.src + ')'}}></div>
);
}
Converting the Profile component
Following the same procedure above, let's convert our Profile component convert it to a functional component.
- Create a function called
Profileand give itpropsas an argument.
function Profile(props){
- Take the return value from our
rendermethod and make that the return value of our function.
<div className="Profile">
<h1 className="Name">{this.props.person.name}</h1>
<p className="Bio">{this.props.person.biography}</p>
<div className="Quote">
<blockquote>“ {this.props.quote.content} ”</blockquote>
<div className="byline">— {this.props.quote.source}</div>
</div>
</div>
-
We change any references to
this.propstoprops. In ourProfilecomponent we need to changethis.propstopropsin multiple places: -
this.props.person.nametoprops.person.name -
this.props.person.biographytoprops.person.biography -
this.props.quote.contenttoprops.quote.content -
this.props.quote.sourcetoprops.quote.source
Here is what our newly created Profile function component looks like:
function Profile(props){
return (
<div className="Profile">
<h1 className="Name">{props.person.name}</h1>
<p className="Bio">{props.person.biography}</p>
<div className="Quote">
<blockquote>“ {props.quote.content} ”</blockquote>
<div className="byline">— {props.quote.source}</div>
</div>
</div>
);
}
Class components
Our App component is a litle more complicated in terms of functionality, so we are going to convert the component to a JavaScript class.
The JavaScript syntax for classes are new-ish as of the ES6 (also known as ES2015/ECMAScript 6/ECMAScript2015) specifications. Classes are not unique to JavaScript. Classes are a common construct used in many languages, but the "under the hood" implementation details of using the class keyword is different in JavaScript compared to other class-based languages, like Java or C++.
What is a class?
In the real world, there are many types of objects, all with specific functions and features. For example, a bicycle is a commonly used object that has 2 wheels, gears, handlebars, brakes and a seat. These are all common properties of a bicycle. While riding a bicycle, you might apply the brakes, shift gears or pedal. Creating a bicycle requires a blueprint to make sure it is built properly, to the correct specifications.
In the programming world, we also make use of "blueprints" or "templates" to build objects. These templates are called classes, and they specify the certain actions (more commonly known as methods) and properties an object has. When we create a new object using a class, we say we are "instantiating an object." We'll often refer to this object as an instance of the class.
When we create components in React, we typically extend the Component class or "template". The Component class React gives us has methods associated with it (like the setState method) that the components we create can use in our subclassed objects.
Objects, classes and prototypes are a fairly complex, but important topic to learn in JavaScript. If you'd like to go more in depth, these blog posts are highly recommended for learning more:
"Understanding Prototypes in JavaScript" by Yehuda Katz
"How to Use Classes and Sleep at Night" by Dan Abramov
"What’s the Difference Between Class & Prototypal Inheritance?" by Eric Elliott
Converting the App component
To convert our App component, we need to do a few things.
- First, we import the
Componentclass from React using this syntax:
mport React, { Component } from 'react';
- Next, we change our code from using
React.createClassto using the JavaScriptclasssyntax:
The first line of our old App component looks like this:
var App = React.createClass({
We need to remove the React.creacteClass function call and replace it with the class keyword. We also need to extend the Component class:
class App extends Component{
- Then, we create a constructor function and pass in
propsso that our component has access to anypropspassed into it.
constructor(props) {
Inside our constructor function we must first call super(props) in this syntax. Calling super() calls the React.Component constructor function. In derived classes, super() must be called before we can use this. Leaving super() out will cause a reference error.
super(props);
- Next, we need to initialize the state of our component. Instead of using the
getInitialStatefunction, we will initialize the state of our component in our constructor function. We can take the object returned from ourgetInitialStatefunction and assign it tothis.statein our constructor:
this.state = {
person: {
name: 'Jack-Edward Oliver',
biography: '26 year old Designer / Developer living in Stockholm. Originally from Oxford, England. Love to make stuff.',
},
image: 'http://static1.squarespace.com/static/55acc005e4b098e615cd80e2/t/57b057398419c2c454f09924/1471025851733/',
quote: {
content: 'Beautiful things don\'t ask for attention',
source: 'The Secret Life of Walter Mitty'
}
- Finally, we'll need to change the syntax of our
renderfunction slightly to look like this:
render() {
return(
<div className="App">
<Image src={this.state.image} />
<Profile person={this.state.person} quote={this.state.quote} />
</div>
);
}
Here is the full result of our new App component:
class App extends Component{
constructor(props) {
super(props);
this.state = {
person: {
name: 'Jack-Edward Oliver',
biography: '26 year old Designer / Developer living in Stockholm. Originally from Oxford, England. Love to make stuff.',
},
image: 'http://static1.squarespace.com/static/55acc005e4b098e615cd80e2/t/57b057398419c2c454f09924/1471025851733/',
quote: {
content: 'Beautiful things don\'t ask for attention',
source: 'The Secret Life of Walter Mitty'
}
};
}
render() {
return(
<div className="App">
<Image src={this.state.image} />
<Profile person={this.state.person} quote={this.state.quote} />
</div>
);
}
}
Try it out!
Check out the Codepen example:
The complete source for this article is also available on Github here.
To start the app, download the code,
cdinto the project directory and type:npm install npm start