React Tips — Conditional Prop Validation, and React Router Basics

John Au-Yeung - Jan 21 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Set isRequired on a Prop if Another Prop is null or Empty with Prop-Types

Prop-types lets us validate another prop with custom validation.

For instance, we can write:

import PropTypes from 'prop-types';

//...

Item.propTypes = {
  showDelete: PropTypes.bool,
  handleDelete: (props, propName, componentName) => {
    if (props.showDelete === true && typeof props[propName] !== 'function') {
      return new Error('handleDelete must be a function');
    }
  },
}
Enter fullscreen mode Exit fullscreen mode

We have the Item component where we set the propTypes property to do some validation.

We have showDelete set to a boolean prop.

And handleDelete is validated by a function that checks if the showDelete prop is true and that the handleDelete prop is a function.

propName is the name of the prop that we’re currently validating.

So propName is the handleDelete prop.

We make sure that if props.showDelete is true , the handleDelete prop is a function.

There’s also the react-required-if package that lets us simplify our code.

For instance, we can write:

import requiredIf from 'react-required-if';
import PropTypes from 'prop-types';

//...

Item.propTypes = {
  showDelete: PropTypes.bool,
  handleDelete: requiredIf(PropTypes.func, props => props.showDelete === true)
};
Enter fullscreen mode Exit fullscreen mode

We make sure that handleDelete is a function when showDelete is true with the requiredIf function.

Wrong Components in a List Rendered by React

If we’re rendering a list of items, we should assign a unique value for the key prop to each item in the list.

For instance, we can write:

<div>
  <div className="packages">
    <div key={0}>
      <button>X</button>
      <Package name="a" />
    </div>
    <div key={1}>
      <button>X</button>
      <Package name="b" />
    </div>
    <div key={2}>
      <button>X</button>
      <Package name="c" />
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

We have a list of items, and we assigned a unique value for each key prop.

This way, they’ll be rendered properly no matter what we do with them.

If we’re rendering an item, we should write:

consr packages = this.state.packages.map((package, i) => {
  return (
    <div key={package}>
      <button onClick={this.removePackage.bind(this, package)}>X</button>
      <Package name={package.name} />
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

We make sure that we pass in a unique value for the key prop.

Then when we manipulate the array and re-render it, everything will be rendered properly.

We should never use the array index as the key since they can change and may not be unique.

How to Create an App with Multiple Pages using React

To let us create an app that has multiple pages in React, we’ve to use React Router to do the routing.

We install it by running:

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

Then we write:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

const Home = () => {
  return <h2>Home</h2>;
}

const About = () => {
  return <h2>About</h2>;
}

const Profile = () => {
  return <h2>Profile</h2>;
}

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/profile">Profile</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/profile">
            <Profile />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}
Enter fullscreen mode Exit fullscreen mode

We created 3 function components which we use as the route’s content.

Then in the App component, we import the Switch component and add the routes inside.

The Route component lets us create the routes.

path is the URL path that we want to map to the component.

And we add the component we want to display inside the Route component.

Link is provided by React Router so that we go to the URL that we want to go to.

It can also work with nested routes, custom links, default routes, query strings, and URL parameters.

We can add nestyed routes by writing:

loads the Topics component, which renders any further <Route>'s conditionally on the paths :id value.import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useRouteMatch,
  useParams
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/topics">Topics</Link>
          </li>
        </ul>

        <Switch>
          <Route path="/topics">
            <Topics />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Topics() {
  let match = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>

      <ul>
        <li>
          <Link to='about'>About</Link>
        </li>
      </ul>

     <Switch>
        <Route path='/about' >
          <About />
        </Route>
      </Switch>
    </div>
  );
}

function About() {
  return <h2>About</h2>;
}
Enter fullscreen mode Exit fullscreen mode

We just nest routes in components to nest them.

Conclusion

We create an app that has multiple pages with React Router.

Also, we can conditionally validate props with a function or a 3rd party library.

And we should always add a key prop with a unique value to each list item.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .