Useful React Tricks for Beginners

Useful React Tricks for Beginners

3 Important Topics every React Developer should understand

ยท

6 min read

For a beginner React may seem like a minefield filled with weird behaviours, uncanny interactions between hooks and whether to use classes or hooks. I hope this small article will aid you in your Frontend Journey as I explain some simple yet effective modern React techniques.

1. Class or Function (Hooks) Components

99% of the time it's better, lighter and easier to use hooks, although classes provide some useful functionalities. A project may have both class & function components defined so you can mix and match if required.

Let's write a simple component which generates a different random value every time we click a button and updates the interface with the new value.

First using Class Component we will get something like this:

class Random extends React.Component {
  constructor() {
    super();
    // define state variables, the more the messier
    this.state = {
      randomValue: 0,
    };
  }

  // function to be called on onClick to update the state
  handleGenerateRandomNumber = () => {
    this.setState({randomValue: Math.round(Math.random() * 1000)});
  }

  render() {
    return (
      <div>
        {/* we use {...} to inject JS code in this HTML like syntax called JSX */}
        <p>Your random value is {this.state.randomValue}</p>
        <button onClick={this.handleGenerateRandomNumber}>
          Generate
        </button>
      </div>
    );
  }
}

// append our component to the root div
React.render(<Random />, document.getElementById('root'));

Whereas with hooks our component would look like this:

import { useState } from React;

// our component is now an arrow function which returns the JSX 
// we want to render
const Random = () => {
  // we declare our state variable by destructuring the return value
  // of useState  and initialize it with 0
  const [randomValue, setRandomValue] = useState(0)

  // our callback function to mutate the state onClick
  const handleGenerateRandomNumber = () => {
    setRandomValue(Math.round(Math.random() * 1000));
  }

  return (
    <div>
      {*/ JSX syntax is mostly identical except the lack of this keyword /*}
      <p>Your random value is {randomValue}</p>
      <button onClick={handleGenerateRandomNumber}>
        Generate
      </button>
    </div>
  )
}

ReactDOM.render(<Random />, document.getElementById('root'))

In the end it's up to you which variant you choose although nowadays hooks are pretty globally accepted as the way to go.

Hooks are:

  • smaller in size (lines) and more verbose
  • easier to understand for someone with no Object Oriented knowledge
  • less complex as they don't use lifecycle methods such as componentDidMount, componentDidUnmount and many others

There are many hooks available but I'll discuss 2 which I consider the most important to understand.

  • useState
  • useEffect

2. How useState works

useState is one of the most important hooks and provides state to our components. State is what makes a component interactive and dynamic but it can also reduce performances in case of frequent state updates if not used properly.

It receives as argument an initial value for the state and returns an array of a current state variable and a setter function to mutate(update) the state.

In our example earlier we saw how the useState hook works for a number variable but what about an object or array?

Let's imagine we have a sign in form and need to store some public information regarding the user details such as email or name.

  // initialize the user with an empty object
  const [user, setUser] = useState({});

  // when the user submits we update the state
  const handleSubmitInfo = (userInfo) => {
    // we can use brackets to extract some properties
    const { email, name } = userInfo;
    // and mutate the state
    setUser({ email, name});
  }

It's the same thing as our previous example but with an object instead of a number.

Let's say we have an array of users which liked a post how do we add a new user to the array?

  // initialize the users with an empty array
  const [users, setUsers] = useState([]);

  // when the user likes we add him to the state
  const handleLikePost = (user) => {
    // we can create a deep copy of the previous state
    // using this neat trick
    const newUsers = JSON.parse(JSON.stringify(users));
    // another way would be using the ES6 spread operator
    // const newUsers = [...users];
    // and add the new user before updating the state
    newUsers.push(user);
    setUsers(newUsers);
  }

It's not that complicated to update the state in the end isn't it ๐Ÿค“?

3. How useEffect works

useEffect is another essential hook which allows us to add a callback function to listen to changes in a certain variable.

It provides 2 arguments

  • callback function to execute on dependency change
  • dependecy array

The dependency array sounds pretty weird and dangerous and it actually is if you forget about it. Not adding the [] argument to useEffect will cause it to trigger on every rerender which can lead to very undesirable situations (such as 'ddos-ing' your own API and losing credit)

Let's say we wanted to make and API call to return a random animal name whenever the component first appears (mounts) on the screen.

We can write something like this

import { useState, useEffect } from "react";

export default function App() {
  const [animalUrl, setAnimalUrl] = useState("");

  useEffect(() => {
    // we make a simple GET request and parse the response as json
    fetch("https://dog.ceo/api/breeds/image/random")
      .then((response) => response.json())
      // and update the img URL
      .then(({ message }) => setAnimalUrl(message));
  }, []);

  // VERY BAD (unless you are certain it's what you want)
  // if we forget to add an empty array then the useEffect
  // callback will execute on every rerender and can result
  // in a neverending loop of requests in our case
  // useEffect(() => {
    // fetch("https://dog.ceo/api/breeds/image/random")
    //   .then((response) => response.json())
    //   .then(({ message }) => setAnimalUrl(message));
  // }); 

  // you can call useEffect multiple times with the same dependency
  // as it improves code readability
  // useEffect(() => {
  // fetch("another api endpoint")
  //   .then((response) => response.json())
  //   .then(({ message }) => { // do something }});
  // }, []);

  return (
    <div>
      <p>Your spirit animal is</p>
      <img src={animalUrl} alt="animal" />
    </div>
  );
}

Another use-case would be if we wanted to make the fetch request only when a modal opens.

import { useState, useEffect } from "react";

export default function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [animalUrl, setAnimalUrl] = useState("");

  // this callback will execute once with the default value
  // and whenever isModalOpen value changes
  useEffect(() => {
    if (isModalOpen) {
      fetch("https://dog.ceo/api/breeds/image/random")
        .then((response) => response.json())
        .then(({ message }) => setAnimalUrl(message));
    }
  }, [isModalOpen]);

  // function to set modal open
  const handleOpenModal = () => {
    setIsModalOpen(true);
  };

  return (
    <div>
      <p>Your spirit animal is</p>
      <button onClick={handleOpenModal}>Open Modal</button>
      {/* conditional rendering of modal */}
      {isModalOpen && (
        <div className="modal">
          <img src={animalUrl} alt="animal" />
        </div>
      )}
    </div>
  );
}

There are many other hooks and techniques in React but that's for another day as this is already an undesirably lengthy and complex post as is.

I hope you enjoyed this guide and would love if you put a ๐Ÿ’œ on it!

ย