React Tips — HTML, State Arrays, and Images

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.

How to Pass HTML Tags in Props

There are several ways to pass HTML tags as props.

One way is to pass JSX expressions as props.

For instance, we can write:

myProp={<div><Foo />Some String</div>}
Enter fullscreen mode Exit fullscreen mode

We can also pass in an HTML string:

myProp="<div>This is some html</div>"
Enter fullscreen mode Exit fullscreen mode

Then we can render it as HTML by writing:

<div dangerouslySetInnerHTML={{ __html: this.props.myProp }}></div>
Enter fullscreen mode Exit fullscreen mode

We set the dangerouslySetInnerHTML prop to render HTML as-is.

It only works with simple HTML and not JSX expressions, components, or other things.

We can also pass in an array of JSX elements:

myProp={["foo", <span>Some other</span>, "bar"]}
Enter fullscreen mode Exit fullscreen mode

We have both strings and HTML in our myProp array.

We can then render this array the way we want.

Also, we can pass in components as the children of another component.

For instance, we can write:

<Foo>
  <div>Some content</div>
  <div>Some content</div>
</Foo>
Enter fullscreen mode Exit fullscreen mode

We have the Foo component that’s wrapped around 2 divs.

In Foo we can render the components inside by referencing this.props.children for class components.

And in function components, we get the children property from the props parameter, which is the first one.

We can also use a fragment:

<MyComponent myProp={<React.Fragment>This is an <b>HTML</b> string.</React.Fragment>} />
Enter fullscreen mode Exit fullscreen mode

Then we can pass in multiple elements without rendering a wrapper.

Implement Authenticated Routes in React Router

We can implement authenticated routes with our own components.

For instance, we can write:

const PrivateRoute = ({ component: Component, authed, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => authed
        ? <Component {...props} />
        : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

We created our own PrivateRouter component that takes the component that we want to protect.

We renamed the component prop to Component to make it uppercase.

Then we render the component if authentication credentials are valid.

Otherwise, we return the Redirect component to redirect to an unprotected page.

Then we can use it by writing:

<PrivateRoute authed={this.state.authed} path='/profile' component={Profile} />
Enter fullscreen mode Exit fullscreen mode

We pass in the component that we want into PrivateRouter to protect it.

React.cloneElement vs this.props.children

We need to use React.cloneElement if we need to do anything other than rendering the children components.

This is because this.prop.children is only a descriptor of the children.

For instance, if we have the following:

render() {
  return(
    <Parent>
      <Child>First</Child>
      <Child>Second</Child>
      <Child>Third</Child>
    </Parent>
  )
}
Enter fullscreen mode Exit fullscreen mode

Then to add a prop to it, we need to write:

render() {
  return (
    <div>
      {React.Children.map(this.props.children, child => {
        return React.cloneElement(child, {
          onClick: this.props.onClick })
      })}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

We’ve to call React.cloneElement to make a clone of each child to add an onClick handler to each child component.

Push into State Array

We can puts into a state array by concatenating the new entries to it.

This way, we don’t mutate the original array.

We don’t want to change the original since it’ll be overwritten on the next render.

For instance, we can write:

const arr = this.state.myArray.concat('new');
this.setState({ myArray: arr })
Enter fullscreen mode Exit fullscreen mode

We can also use the spread operator:

this.setState({ myArray: [...this.state.myArray, 'new'] })
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] })
Enter fullscreen mode Exit fullscreen mode

The first one adds a single entry as we have above.

The 2nd merged the 2nd array into the first one and return it.

If we need to set the new array value based on the current array’s value, we can call setState with a callback that returns a new array based on the previous one.

For instance, we can write:

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new"]
}))
Enter fullscreen mode Exit fullscreen mode

We return the state with a new array.

Load Local Images with React

We can load local images by importing the image as a module.

For instance, we can write:

import React from 'react';
import logo from './logo.png';

function Header() {
  return <img src={logo} alt="Logo" />;
}
Enter fullscreen mode Exit fullscreen mode

We import the image as a module and we put it straight into the src prop.

We can also do the same with require :

<img src={require('./logo.png')} />
Enter fullscreen mode Exit fullscreen mode

Conclusion

We can add images by importing them.

There are several ways to pass HTML as props.

React.cloneElement is required for adding props to children.

There are several ways to push new data to a state array.

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