React Tips — Conditional Prop Validation, and React Router Basics
Tags: react, webdev, programming, javascript
Published: 2021-01-21 21:44:36

**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');
    }
  },
}
```

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)
};
```

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>
```

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>
  );
});
```

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
```

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>
  );
}
```

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>;
}
```

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.