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
Image
component - A
Profile
component - An
App
component
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
Image
component:
function Image(props){
- Take the
return
value from ourrender
method in our original component and make that thereturn
value of our function.
return (
<div className="Image" style={{backgroundImage: 'url(' + this.props.src + ')'}}></div>
);
- If we have any
props
in our component, we need to remove thethis
keyword, since theprops
are passed in as a parameter to the function. In ourImage
component, we changethis.props.src
toprops.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
Profile
and give itprops
as an argument.
function Profile(props){
- Take the return value from our
render
method 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.props
toprops
. In ourProfile
component we need to changethis.props
toprops
in multiple places: -
this.props.person.name
toprops.person.name
-
this.props.person.biography
toprops.person.biography
-
this.props.quote.content
toprops.quote.content
-
this.props.quote.source
toprops.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
Component
class from React using this syntax:
mport React, { Component } from 'react';
- Next, we change our code from using
React.createClass
to using the JavaScriptclass
syntax:
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
props
so that our component has access to anyprops
passed 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
getInitialState
function, we will initialize the state of our component in our constructor function. We can take the object returned from ourgetInitialState
function and assign it tothis.state
in 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
render
function 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,
cd
into the project directory and type:npm install npm start