DEV Community

Manjunath
Manjunath

Posted on

React Basics – State, Props & Functional Components

Introduction

React is among the more popular front-end libraries in use today. However, beginners might find it hard to get started with the concept in React because they're different compared to traditional programming concepts like that of Java. Different aspects like how components work, component composition and hierarchy, state, props, and functional programming concepts need to be considered beforehand. This guide attempts to make things simpler by providing readers with an easy and simple way to start using React.

Setting up React

There are two popular ways to set up React. If you're looking to set up React real quick, you can use the one-page setup by including the scripts from unpkg.

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.js"></script>

Otherwise, you can set up the React environment by running create-react-app:

npx create-react-app my-app

Alternatively, you can also use yarn. \

yarn create react-app my-app

Here is the structure of files created by yarn:

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js

To start your application, you'll need to run npm run start or yarn start.

Components

Components are the building blocks of a React application. You can build your entire application using just components. They are reusable and independent blocks of code. They're are two types of Components and the classification is popularly known under different names:

  1. Class vs Functional Component
  2. Smart vs. Dumb components
  3. Container vs. Presentational components
  4. Stateful vs. Stateless components

Although the components are known under different names, the basis of classification is relatively similar. Class components use ES6 classes whereas Functional components are based on JavaScript functions.

Since the central aspect of React is components, a better understanding of how to organize components in React is essential. We'll cover that in this article by defining the differences between functional components and class components. Here's a basic example that demonstrates the difference between them.

Replace the src/App.js with the following lines:

class App extends Component { \

render() { \ const message = `This is the App Component.`; \ return ( \ <div>{message}div> \ ); \ } \ }

The App component here is an ES6 class and hence we'll call them class components. It extends the Component class which is a part of the React API. It contains a 'render' method which comprises a return statement. Everything inside the return statement is rendered in the browser. You can render HTML elements or other components (read Composition Hierarchy).

If you remove the render method, React will throw an error because the class component needs to include a render method. However, other methods are optional. ReactDOM.render() renders the App component in a div element using the id 'root'.

But remember, this is not the only way that you can create components. You can also use functional components as follows:

function App(props){

const message = `This is the App Component.`; \ return <div>{message}div> \ }

So, the next obvious question is, what are props?

Props

Props refer to properties that are passed to child components by the parent components. For instance, if you need to pass a value from a parent component to a child component, you can pass them down as properties or props.

class App extends React.Component {
 render() {
  return <Child value="SOS" />;  
 }
}
class Child extends React.Component{
 render(){
  return <h3>The value passed from parent is {this.props.value}</h3>;
 }
}

You can replace the class component we created earlier with this functional component and it will appear just the same in the browser.

function Child (props) {
 return <h3>The value passed from parent is {props.value}</h3>;
 }
}

So, why do we have two different types of components when you can stick with just one? That's because class components have certain features that are bestowed upon them whereas functional components lack these features.

Functional Components

Functional components have very little baggage compared to the more popular class components. They're theoretically faster than class components, but that might not be relevant if you're running a small application with very limited components.

The drawbacks with Functional component is that you can't use the state and lifecycle hooks inside functional components. Instead, they're meant to be just presentational component without any logic of their own. Unlike class components, you can't also use componentDidMount and other similar lifecycle hooks. But instead, you can wrap a part of your web UI as follows:

const Button = props => (
   <button className="our_button" onClick={props.onClick}>
      {props.label}
   </button>
);

Here are a few good things about functional components:

  1. They are reusable compared to class components
  2. Functional components can potentially have a better performance
  3. They're easy to debug

So, you can wrap your buttons, input fields etc. inside functional components and pass everything that's required by that component as props. However, certain other logic involves making API calls and then storing the result in the state. That's where class component come in handy.

Class Components

State

Similar to Props, the state also contains data, however, with a few differences.

Props contain data that are communicated by the parent component. On the other hand, the state contains private data that's local to the component. Unlike props which are read-only value, State is readable and writable by the component. It stores data that changes between different renderings of the component.

Here is an example -

class App extends React.Component {
 constructor(){
  super();
  this.state = {name :"Foo Bar"};
 }
 changeName(){
  this.setState({name : "Lorem Ipsum"});
 }

 render(){
  return (
   <div>
     <h3>Hello {this.state.name}</h3>
     <button type='button' onClick=this.changeName.bind(this)}>
      Save
     </button>
   </div>
  );
 }
}

As demonstrated in the example above, once a constructor is initialized, it can be used in a render method. Similar to props, the state can be accessed via the 'this.state' object. On clicking the Save button, users are able to change the value name of the state to their choosing. this.setState() takes care of updating the state.

setState()

this.setState() is a part of the React API that's used to modify the state. This is available in React Component by default and is pretty much the only way to change state. When an object is being passed as a parameter to setState, React asynchronously make changes to the state by modifying the keys that are passed to it. React will look at the passed object and will change only the provided keys of the state with the provided values.

Life Cycle Methods

React provides users with specific special methods known as Life Cycle Hooks. These life cycle hooks execute at specific times in the life cycle of a component. Fortunately, users have the ability to include their own functionality in these life cycle hooks. You can define lifecycle hooks inside the components to define what a component does when it mounts, receives new props, unmounts etc. Here are some examples of commonly used life cycle hooks.

componentDidMount()

Mounting refers to the time taken when the component is initially rendered in the browser. componentDidMount() executes after the component is mounted. This is a good place to fetch specific data or initiate anything.

Here is an example of the events that happen when a component mounts. \

  1. Data gets fetched by making a call to a API endpoint

  2. The response is being stored into the state using this.setState()

 componentDidMount(){
    componentDidMount() {
    fetch(API + DEFAULT_QUERY)
      .then(response => response.json())
      .then(data => 
         this.setState({ 
           person: 
               {
                name: data.name, age: data.age
               }
        })
     );
    }
 }

\

componentWillUnMount()

This gets executed just before the component unmounts. If you want to clear some global state (stored in Redux store) or remove some event listener, this should be the where your code goes.

For instance, if you've set up an event listener like for scroll, you can remove it as follows:

componentWillUnmount() {
       window.removeEventListener('scroll', this.onScroll, false);
   }

componentDidUpdate()

As the name suggests, componentDidUpdate() executes once the component is completely updated. This is where data changes and related modifications are handled. It may be possible that users may need to handle specific network requests, or perform calculations based on the changed data. In scenarios like this, componentDidUpdate() is the place to be.

Here is an example of this in action –

class App extends React.Component {
 constructor(){
  super(); 
  this.state = {
   person : {name : "" , age : ""}
  };
 }
 componentDidMount(){
    componentDidMount() {
    fetch(API + DEFAULT_QUERY)
      .then(response => response.json())
      .then(data => 
         this.setState({ 
           person: 
               {
                name: data.name, age: data.age
               }
        })
     );
    }
 }

componentDidUpdate(prevProps) {
  // Typical usage (don't forget to compare props):
  if (this.props.person.name !== prevProps.person.name) {
    this.fetchData(this.props.name);
  }
}


 render(){
  return (
   <div>
    <p>Name : {this.state.person.name}</p>
    <p>Age : {this.state.person.age}</p>
   </div>
  );
 }
}

Our first state consists of two distinct properties, viz. name and age, Both of these have an empty string as value. In componentDidMount() users can set the state and modify the name as needed.

Final Words - Choosing the right component

So, how do you choose between functional components and class components? I usually start with functional components and then shift to class components if either state or component life cycles is required. If not, you can just stick with functional components.

You can use functional components for anything that doesn't require state or is meant to serve as a UI element. If it has complex logic, then you should probably fit it inside a class component.

Top comments (0)