PropTypes

Since JavaScript is a dynamically typed language, we don’t really have a way to enforce the type of a variable at compile time. If we pass invalid types, they will fail at runtime or give weird results if the types are compatible but not what we expect.

Flow and TypeScript help a lot, but React has a way to directly help with props types. Even before running the code, our tools (editors, linters) can detect when we are passing the wrong values:

import PropTypes from 'prop-types';
import React from 'react' 

class BlogPostExcerpt extends Component { 
  render() { 
    return ( 
      <div> 
        <h1>{this.props.title}</h1> 
        <p>{this.props.description}</p> 
      </div> 
    ) 
  } 
}

BlogPostExcerpt.propTypes = { 
  title: PropTypes.string, 
  description: PropTypes.string 
};

export default BlogPostExcerpt

Which types can we use

These are the fundamental types we can accept:

  • PropTypes.array
  • PropTypes.bool
  • PropTypes.func
  • PropTypes.number
  • PropTypes.object
  • PropTypes.string
  • PropTypes.symbol

We can accept one of two types:

PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),

We can accept one of many values:

PropTypes.oneOf(['Test1', 'Test2']),

We can accept an instance of a class:

PropTypes.instanceOf(Something)

We can accept any React node:

PropTypes.node

or even any type at all:

PropTypes.any

Arrays have a special syntax that we can use to accept an array of a particular type:

PropTypes.arrayOf(PropTypes.string)

We can compose an object property by using:

PropTypes.shape({ 
  color: PropTypes.string, 
  fontSize: PropTypes.number 
})

Requiring properties

Appending isRequired to any PropTypes option will cause React to return an error if that property is missing:

PropTypes.arrayOf(PropTypes.string).isRequired, PropTypes.string.isRequired,

Default values for props

If any value is not required, we need to specify a default value for it if it’s missing when the Component is initialized.

BlogPostExcerpt.propTypes = { 
  title: PropTypes.string, 
  description: PropTypes.string 
}

BlogPostExcerpt.defaultProps = { 
  title: '', 
  description: '' 
}

Some tooling, like ESLint, has the ability to enforce defining the defaultProps for a Component with some propTypes not explicitly required.

How props are passed

When initializing a component, pass the props in a way similar to HTML attributes:

const desc = 'A description' 
//... 
<BlogPostExcerpt title="A blog post" description={desc} />

We passed the title as a plain string (something we can only do with strings!), and the description as a variable.

Children

A special prop is children. That contains the value of anything that is passed in the body of the component. For example:

<BlogPostExcerpt title="A blog post" description={desc}> 
  Something 
</BlogPostExcerpt>

In this case, inside BlogPostExcerpt we could access “Something” by looking up this.props.children.

While Props allow a Component to receive properties from its parent (they could be “instructed” to print some data for example), state allows a component to take on a life of its own, and be independent from the surrounding environment.

Remember: only class-based Components can have a state. So if you need to manage state in a stateless (function-based) Component, you first need to “upgrade” it to a Class component:

const BlogPostExcerpt = () => { 
  return ( 
    <div>
      <h1>Title</h1>
      <p>Description</p> 
    </div> 
  )
}

becomes:

import React, { Component } from 'react'

class BlogPostExcerpt extends Component { 
  render() { 
    return (
      <div>  
        <h1>Title</h1> 
        <p>Description</p>
      </div>
    ) 
  } 
}

Setting the default state

In the Component constructor, initialize this.state. For example, the BlogPostExcerpt component might have a clicked state:

class BlogPostExcerpt extends Component {
  constructor(props) { 
    super(props) 
    this.state = { clicked: false } 
  }

  render() { 
    return (
      <div> 
        <h1>Title</h1>
        <p>Description</p> 
      </div> 
    ) 
  } 
}

Accessing the state

The clicked state can be accessed by referencing this.state.clicked:

class BlogPostExcerpt extends Component {
  constructor(props) { 
    super(props)
    this.state = { clicked: false }
  }

  render() { 
    return (
      <div> 
        <h1>Title</h1> 
        <p>Description</p> 
        <p>Clicked: {this.state.clicked}</p> 
      </div> 
    ) 
  } 
}

Mutating the state

A state should never be mutated by using

this.state.clicked = true

Instead, you should always use setState() instead, passing it as an object:

this.setState({ clicked: true })

The object can contain a subset, or a superset, of the state. Only the properties you pass will be mutated. The ones omitted will be left in their current state.

Why you should always use setState()

The reason is that using this method, React knows that the state has changed. It will then start the series of events that will lead to the Component being re-rendered, along with any DOM updates.

State is encapsulated

A parent of a Component cannot tell if the child is stateful or stateless. The same goes for children of a Component.

Being stateful or stateless (functional or class-based) is entirely an implementation detail that other components don’t need to care about.

This leads us to Unidirectional Data Flow

Unidirectional Data Flow

A state is always owned by one Component. Any data that’s affected by this state can only affect Components below it: its children.

Changing a state on a Component will never affect its parent, or its siblings, or any other Component in the application — just its children.

This is the reason that, many times, the state is moved up in the Components tree.

Moving the State Up in the Tree

Because of the Unidirectional Data Flow rules, if two components need to share a state, the state needs to be moved up to a common ancestor.

Often, the closest ancestor is the best place to manage the state, but it’s not a mandatory rule.

The state is passed down to the components that need that value via props:

class Converter extends React.Component { 
  constructor(props) { 
    super(props)
    this.state = { currency: '€' } 
  }

  render() { 
    return ( 
      <div> 
        <Display currency={this.state.currency} />
        <CurrencySwitcher currency={this.state.currency} />
      </div> 
    ) 
  } 
}

The state can be mutated by a child component by passing a mutating function down as a prop:

class Converter extends React.Component { 
  constructor(props) { 
    super(props) 
    this.state = { currency: '€' } 
  }

  handleChangeCurrency = (event) => { 
    this.setState({ 
      currency: this.state.currency === '€' ? '$' : '€' 
    }) 
  }

  render() { 
    return ( 
      <div> 
        <Display currency={this.state.currency} /> 
        <CurrencySwitcher currency={this.state.currency} handleChangeCurrency={this.handleChangeCurrency} /> 
      </div> 
    ) 
  } 
}

const CurrencySwitcher = (props) => { 
  return ( 
    <button onClick={props.handleChangeCurrency}> 
      Current currency is {props.currency}. Change it! 
    </button> 
  ) 
}

const Display = (props) => { 
  return ( 
    <p>Current currency is {props.currency}.</p> 
  ) 
}
W5hfnSrCoSOqkbTNbDn0b1bOocYiHkO70ZgB

Related Posts

What is the DOM? Document Object Model Meaning in JavaScript

If you have just started learning JavaScript, you might have heard of the DOM. But what is it exactly? In this article, I will explain what the…

What is a JSON File? Example JavaScript Code

JSON stands for JavaScript Object Notation. A JSON file has .json as its extension and the data inside are represented in a key:value pair, just like a…

JavaScript split() a String – String to Array JS Method

If you need to split up a string into an array of substrings, then you can use the JavaScript split() method. In this article, I will go over the…

Events

React provides an easy way to manage events. Prepare to say goodbye to addEventListener 🙂 In the previous article about the State you saw this example: If you’ve been…

React Components

What is a React Component? A component is one isolated piece of the interface. For example, in a typical blog homepage, you might find the Sidebar component…

Beginner’s Guide to React

React is a JavaScript library that aims to simplify the development of visual interfaces. Developed at Facebook and released to the world in 2013, it drives some…