React-js is a JavaScript framework that allows us as developers to encapsulate code to make it more reusable. These encapsulated code snippets are called components. They can hold their own logic and state without interfering with what’s going on in the Document Object Model (DOM).
Abstracting portions of your website into these smaller bite-size components to pass data around allows your code to become reusable and more DRY (Don’t Repeat Yourself). There are two main types of components that you will encounter in React: Functional and Class Components.
At a very high level, React components are basically JavaScript functions that accept props as a parameter and return some React elements that basically describe what should be on the screen:
import React from 'react'; import ReactDOM from 'react-dom'; const Greeting = (props) => { return ( <div> Hello, {props.name} </div> ); }; const element = <Greeting name="Yolanda" />; ReactDOM.render( element, document.getElementById('root') )
The React element in this case here is a <div>
with some text in it. That text uses a props object that has been passed into the component. That props object will pass data down to children components from their parents.
In this instance, the prop that has been passed down is name. Element represents the parent.
Any property you pass into the <Greeting
/>
component will make it to the props object and be available to use inside Greeting. This makes Greeting super reusable since we can pass in any name we would like into the component.
Functional Components
Functional components, as we mentioned earlier, are basically JavaScript functions. You can use EcmaScript 5 (ES5) or EcmaScript a6 (ES6) syntax when creating React components. As a rule of thumb, React components must be Capitalized to indicate they are indeed components.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Basic React Component</title> </head> <body> <!-- App is inserted at thr root node --> <div id="root"></div> <!-- React CDN --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <!-- React-DOM CDN --> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <!-- React Components can be rendered here --> <script async> 'use strict'; const element = React.createElement; function Greeting() { return element('h4', null , `Hello, World!`); }; function App() { return element(Greeting); }; const domContainer = document.querySelector('#root'); ReactDOM.render(element(App), domContainer); </script> </body> </html>
This is a mocked, working example of what an ES5 functional component looks like when we are not using JSX, but plain vanilla JavaScript. Don’t worry too much about what’s going on in the HTML. Focus on the JavaScript logic: we have an element that’s being created, a function that’s returning something and then that function is being rendered to some sort of ReactDOM.
What JSX – short for JavaScript XML Extension – basically allows us to do is to write HTML in our JavaScript to make it more akin to what we are used to seeing in HTML. In the code example above, we are purely using JavaScript to create our HTML element and then using React’s createElement method to insert an <h4>
into the DOM at the <div id=”root />.
If we were to scale our application – make our application much bigger than it is – this type of writing would become cumbersome fairly quickly. JSX was created basically as syntactic sugar for the React.createElement method and allows us to scale our apps much quicker.
Functional components can be written ES5 or ES6. This is an example of what both an ES5 and an ES6 functional component looks like using JSX:
ES5 Functional Component
import React from 'react'; import ReactDOM from 'react-dom'; function Animal(props) { const element = <h1>My cat's name is {props.name}</h1>; return element; } function App() { return <Animal name="Marshmallow"/> }; const domContainer = document.querySelector('#root'); ReactDOM.render(<App/>, domContainer);
ES6 Functional Component
const Animal = (props) => { const element = <h1>My cat's name is {props.name}</h1>; return element; } const App = () => { return <Animal name="Marshmallow"/> }; const domContainer = document.querySelector('#root'); ReactDOM.render(<App/>, domContainer);
Prior to React v.16, functional components were known as stateless components. This means that the main purpose of the component was to be presentational – to look good on the page. Quite often, data was passed to these functional components so that they could display something on the user interface.
With the advent of React v.16 that all changed. We will get into that in a little bit. For right now, just know that functional components exist to receive some sort of data from a parent or from some global object to present something to the client.
Class Components
Class components are a little more complicated than “just” a JavaScript function. Class components in React borrow the concept of the ES6 JavaScript class. The structure of a class in JavaScript is pretty much an object that has attributes and methods associated with it. We use the this
keyword to access an instance of that object and interact with it.
In React, for the most part, the structure is the same. React class components are an instance of an object and this object has what we call state. At a high level, state is just data that the component holds – think of it just as another way to set up attributes and bind it to the class. As a developer you can then do whatever you would like with that data: present it on screen, pass it around to other components, use it to do other logic, etc.
An ES6 class component is always capitalized, just like with functional components – that is a React rule so that the transpiler knows it’s a component. Because we are inheriting the component structure from React itself, we have to extend React’s Component
class. Inside that block of code is where we will put our state:
import React from 'react'; import ReactDOM from 'react-dom'; import Name from './Name'; // the 'this' keyword needs to be used when we are talking about an instance of a class. So it will go in front of your methods and state when referring to it in your render method. class Animal extends React.Component { constructor(props) { super(props); this.state = { species: ['fox', 'tiger', 'bear', 'kangaroo', 'fish', 'cat', 'dog', 'squirrel'] } } render() { return ( <div> {this.state.species.map(animal => { return <Name animal={animal}/> })} </div> ) } } ReactDOM.render(<Animal />, document.getElementById('root'));
State is an object full of properties and values. Our state here has a property of species and its value is an array full of animals. To refer to or interact with this array at all, we use this.state.species.
The purpose of the class component above is to pass the name of the animal down to the <Name />
component. The <Name />
component’s job is to do something with that data when it gets it. The Animal’s state will become part of a props object when it is passed to a functional or other class component. It will be able to be accessed in child components as long as it keeps getting passed down.
Just remember that in React, data flows down from parent component to child component only one level. You must pass it down another level if you need the data in the parent’s grandchild component.
Another feature of class components in React is that we have access to and use lifecycle methods to keep track of our state. React lifecycles typically have three phases: They are created (Mounting), they live (Update) and they die (Unmounting). There are methods to access and/or change state at each of the stages of the lifecycle method:
- ComponentDidMount() – this is the lifecycle method where we would make AJAX requests/network requests to initialize state. Use this.setState() to load your retrieved data into state.
- ComponentDidUpdate() – any updates to state occur here after a user has interacted with the application.
- ComponentDidUnmount() – this is a cleanup function that occurs when the component unmounts. It’ll take care of timers, AJAX requests, etc.
There are more lifecycle methods than these – those listed are just the main ones. Please see React documentation for more information about these methods.
Finally, in contrast to the functional component’s return statement, class components use a render()
method. This method is invoked after ReactDOM.render() passes the Animal component and React calls its constructor. State is then initialized and then the render method is called to actually put content on the screen.
Whew! That’s a lot of information.
Just remember that functional components prior to React v. 16 were primarily presentational – they didn’t handle state – they just displayed it. Class components detailed all the state logic for us and passed the information down to other components as props.
Functional Components and useState()
In 2018, React introduced the idea of React Hooks. Hooks are a clean and concise way of utilizing lifecycle methods and state inside a Functional Component.
Most everything is very similar to everything we have covered so far. We have some state, we need to do stuff with it, and we need to pass it somewhere else. The main objectives are the same. The syntax is much cleaner – it just requires a little bit of getting used to.
"Career Karma entered my life when I needed it most and quickly helped me match with a bootcamp. Two months after graduating, I found my dream job that aligned with my values and goals in life!"
Venus, Software Engineer at Rockbot
What I would do is bookmark this site, practice, and get some repetitions in for class components, really understand how the data flow works in React, and then come back here to finish learning about stateful functional components.
Let’s start out with the code that we had before:
import React from 'react'; import ReactDOM from 'react-dom'; const Animal = (props) => { const element = <h1>My cat's name is {props.name}</h1>; return element; } const App = () => { const [ state, setState ] = useState('Marshmallow'); return <Animal name={state}/> }; const domContainer = document.querySelector('#root'); ReactDOM.render(<App/>, domContainer);
We have two components, one Animal and one App. It looks like App is returning Animal and passing in a prop called name with a value of “Marshmallow”.
Believe it or not, there isn’t much we have to do to convert this into some stateful logic. Let’s take a look at the <App> component. We’re are going to follow these steps:
import React, {useState} from 'react';
— this line will import our hook, useState.
const [ state, setState ] = useState('Marshmallow');
– this line initializes our state. State and setState here are arbitrary words. You can name these whatever you’d like. It’s customary to name them after what the value is.
– state is our actual state. The initial state is inside the parentheses in useState().
– setState is similar to this.setState(). This is the method that will change our state as we journey through our application.
return <Animal name={state}/>
– replace “Marshmallow” with {state}. When we need to write JavaScript in JSX, we use curly braces. Curly braces here allows us to pass in our variable.
One of the features that defined class components, the React Lifecycle, with its various methods, is skimmed down to one basic hook that encapsulates all the methods! The useEffect() hook can mount, update and unmount the React component it’s in.
Conclusion
Prior to React v. 16, functional components were purely used as a presentational view layer with no use of state except as props that were passed down from class components. Class components held all of the state of the application and passed the data around. Class components utilized life cycle methods that mounted, updated and unmounted our React component. We also found that React Hooks, a new pattern released by React in version 16, allows for functional components to be stateful and have it’s own version of lifecycle methods.
It’ll be important to be familiar with all of the different types of components even though React Hooks is becoming more popular – legacy code will probably use class components for a while and will still need to be understood so you can work with it!
About us: Career Karma is a platform designed to help job seekers find, research, and connect with job training programs to advance their careers. Learn about the CK publication.