React Tips — Elements and Caching Values

John Au-Yeung - Jan 23 '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 the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at various less common features that are helpful for developing React apps.

Create React Elements with Strings

We can reference React elements with strings instead of JSX. HTML elements can be written with strings instead of JSX.

For instance, we can write the following code:

import React from "react";

const Component = "div";

export default function App() {
  return <Component className="App">hello</Component>;
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we have Component set to 'div' , which means that Component is a div element. This is good because we can change the Component ‘s element tag dynamically without hassle.

For instance, we can make a toggle to switch between div and p as follows:

import React from "react";

export default function App() {
  const [Component, setComponent] = React.useState("div");
  return (
    <>
      <button
        onClick={() =>
          setComponent(Component => (Component === "div" ? "p" : "div"))
        }
      >
        Toggle Tag
      </button>
      <Component className="App">hello</Component>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we have a button to toggle the tag of Component between div and p.

Therefore, when we click the button, we’ll see that the tag of Component switches between div and p as we click the button.

Retain Previous Values

We can use the useRef hook to retain the previous value of a prop or state.

For instance, we can keep the old value and the new value of a state as follows:

import React from "react";

export default function App() {
  const [name, setName] = React.useState("bob");
  const prevNameRef = React.useRef("");

  React.useEffect(() => {
    prevNameRef.current = name;
  }, [name]);

  const prevName = prevNameRef.current;

  return (
    <div>
      <button
        onClick={() => setName(name => (name === "bob" ? "jane" : "bob"))}
      >
        Toggle Name
      </button>
      <p>Current name:</p>
      <p>{name}</p>
      <p>Previous name:</p>
      <p>{prevName}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the name state and the setName function to set the value of name .

Then in the button, we call the setName function when we click it. It toggles between 'bob' and 'jane' .

In the useEffect hook, we watch the value of name , which sets the prevNameRef.current to name to keep the original value. Then we set prevNameRef.current to prevName so to keep things short in the return statement.

In the end, we’ll see the old and new values display in the returned JSX.

Use React.useRef for Flexible Non-Stale Value Checks

One way to check if some data is loaded when the component loads are to use the useRef hook to keep track of whether the piece of data is loaded.

For instance, we can write the following code to do that:

import React from "react";

export default function App() {
  const [name, setName] = React.useState("");
  const loaded = React.useRef(false);

  React.useEffect(() => {
    if (!loaded.current) {
      setName("bob");
    }
    loaded.current = true;
    return () => (loaded.current = false);
  });

  return <div>{name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we check the useEffect callback that checks if loaded.current is true . If it’s not, then we call setName to set the name state’s value.

In the useEffect callback, we also have:

return () => (loaded.current = false);
Enter fullscreen mode Exit fullscreen mode

to reset loaded.current to false when App unloads.

Therefore, we’ll see that the component loads with the name ‘bob’ displayed.

Memoize Values with the useMemo Hook

We can also use the useMemo hook to create a memoized values, which means that it’s cached as long as it or its dependencies don’t change.

useMemo runs during rendering. Therefore, we shouldn’t run anything that we wouldn’t do during rendering.

It’s used as a performance optimization, but it’s not a guarantee of the integrity of the value because it might change later.

For instance, we can use it as follows:

import React from "react";

export default function App() {
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");
  const name = React.useMemo(() => `${firstName} ${lastName}`, [
    firstName,
    lastName
  ]);

  return (
    <div>
      <input value={firstName} onChange={e => setFirstName(e.target.value)} />
      <input value={lastName} onChange={e => setLastName(e.target.value)} />
      <p>{name}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we used useMemo to watch firstName and lastName ‘s values and then derive a new value name from combining the 2.

Then when we enter text into the input, we’ll see that it updates the value of name . However, it’ll cache the existing value if firstName or lastName don’t change.

Conclusion

We can use the useRef and useMemo hooks to cache data. Also, we can create HTML elements with strings. This means that we can render HTML elements dynamically.

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