react.js

How to Get the Value of a Form Input on Submit in React

To get the value of form input on submit in React:

  1. Create a state variable to store the value of the input.
  2. Set an onChange event handler on the input to update the state variable when the input’s value changes.
  3. Set an onSubmit event handler on the form element.
  4. Access the value of the input field in the onSubmit event handler.

For example:

App.js

import { useState } from 'react';

export default function App() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [message, setMessage] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();

    setMessage(`Hello ${firstName} ${lastName}!`);
    setFirstName('');
    setLastName('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        id="firstName"
        name="firstName"
        value={firstName}
        placeholder="First Name"
        onChange={(event) =>
          setFirstName(event.target.value)
        }
      />

      <br />
      <br />

      <input
        type="text"
        id="lastName"
        name="lastName"
        value={lastName}
        placeholder="Last Name"
        onChange={(event) => {
          setLastName(event.target.value);
        }}
      />

      <br />
      <br />

      <button type="submit">Submit</button>

      <br />
      <br />

      <h2>{message}</h2>
    </form>
  );
}
The input values are used to display a message on form submit.

With the useState() hook we create a state variable to store the current value of each input field. We also created another state variable (message) that will be updated with the values of the input fields after the user submits the form.

We set an inline onChange event handler on each input field to make the handler get called whenever the input field changes. In each handler, we use the target property of the Event object the handler receives to access the input element object. The value property of this object contains the input value, so we pass it to the state update function to update the value of that particular input.

The button element in the form has a type of submit, so every time the user clicks it, the submit event is triggered. We set an onSubmit event handler on the form to listen to this event. In this handler, we call preventDefault() on the Event object, to prevent the page from refreshing when the form is submitted.

To get the input values in this event handler after the form is submitted, we simply access the firstName and lastName state variables.

Get input value on form submit with event.target

We can also get the value of a form input on submit using the target property of the Event object. This is useful in cases where we don’t track the input value with a state variable, i.e., an uncontrolled input.

App.js

import { useState } from 'react';

export default function App() {
  const [message, setMessage] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();

    const firstName = event.target.firstName.value;
    const lastName = event.target.lastName.value;
    setMessage(`Hello ${firstName} ${lastName}!`);

    event.target.reset();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        id="firstName"
        name="firstName"
        placeholder="First Name"
      />

      <br />
      <br />

      <input
        type="text"
        id="lastName"
        name="lastName"
        placeholder="Last Name"
      />

      <br />
      <br />

      <button type="submit">Submit</button>

      <br />
      <br />

      <h2>{message}</h2>
    </form>
  );
}

In an onSubmit event handler, the target property of the Event object returns the form element object (of type HTMLFormElement).

Because we set the name prop on the input element, the form element object will contain a property with the same name that returns the input element object, i.e., after setting name to firstName on an input element, we can access the element object for this input with the firstName property on the form element object.

After getting the value of each input and displaying the message, we call the reset() method on the form element object to restore the default values of the form’s input elements. This is how we clear the text in the input fields in this example since they’re not controlled by state variables.

Get input value on form submit with ref

We can also use a component ref to get the value of an uncontrolled form input on submit in React.

App.js

import { useState, useRef } from 'react';

export default function App() {
  const [message, setMessage] = useState('');
  const firstNameRef = useRef(undefined);
  const lastNameRef = useRef(undefined);

  const handleSubmit = (event) => {
    event.preventDefault();

    const firstName = firstNameRef.current.value;
    const lastName = lastNameRef.current.value;

    setMessage(`Hello ${firstName} ${lastName}!`);

    event.target.reset();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        id="firstName"
        name="firstName"
        placeholder="First Name"
        ref={firstNameRef}
      />

      <br />
      <br />

      <input
        type="text"
        id="lastName"
        name="lastName"
        placeholder="Last Name"
        ref={lastNameRef}
      />

      <br />
      <br />

      <button type="submit">Submit</button>

      <br />
      <br />

      <h2>{message}</h2>
    </form>
  );
}

The data in a controlled input is handled by React state, but for an uncontrolled input, it is handled by the DOM itself. This is why the input in this example above doesn’t have a value prop or onChange event handler set. Instead, we access the input field’s value with a React ref. The DOM updates this value when the text in the input is changed.

For each input, we create a ref object with the useRef() hook and set it to the ref prop of the input. Doing this sets the current property of the ref object to the DOM object that represents the input element.

useRef() returns a mutable ref object that doesn’t change value when a component is updated. Also, modifying the value of this object’s current property doesn’t cause a re-render. This is in contrast to the setState update function returned from useState().

Although the React documentation recommends using controlled components, uncontrolled components offer some advantages. You might prefer them if the form is very simple and doesn’t need instant validation, and values only need to be accessed when the form is submitted.

How to Get an Input Value On Change in React

To get the value of an input on change in React, set an onChange event handler on the input, then use the target.value property of the Event object passed to the handler to get the input value.

For example:

App.js

import { useState } from 'react';

export default function App() {
  const [message, setMessage] = useState('');

  const handleChange = (event) => {
    // 👇 Get input value from "event"
    setMessage(event.target.value);
  };

  return (
    <div>
      <input
        type="text"
        id="message"
        name="message"
        onChange={handleChange}
      />

      <h2>Message: {message}</h2>
    </div>
  );
}
Getting an input value on change in React.
The message is updated when the input value changes.

Here we create a state variable (message) to track the input value. By setting an onChange event handler, the handler function will get called whenever the text in the input field changes.

The handler function will be called with an Event object containing data and allowing actions related to the event. The target property of this object lets us access the object representing the input element.

This input element object has a value property which returns the text currently in the input field. So we call the setMessage() function with this property as an argument to update the message variable with the input value, and this reflects on the page after the DOM is updated.

How to Get the Value of an Input When a Button is Clicked in React

Related: How to Get an Input Field’s Value in React

To get the value of an input field on button click in React:

  1. Create a state variable to store the value of the input field.
  2. Set an onChange event handler on the input to update the state variable when the input field value changes.
  3. Set an onClick event handler on a button element.
  4. Access the state variable in the event handler.

For example:

App.js

import { useState } from 'react';

export default function App() {
  const [message, setMessage] = useState('');

  const [updated, setUpdated] = useState(message);

  const handleChange = (event) => {
    setMessage(event.target.value);
  };

  const handleClick = () => {
    // 👇 "message" stores input field value
    setUpdated(message);
  };

  return (
    <div>
      <input
        type="text"
        id="message"
        name="message"
        onChange={handleChange}
        value={message}
      />

      <h2>Message: {message}</h2>

      <h2>Updated: {updated}</h2>

      <button onClick={handleClick}>Update</button>
    </div>
  );
}
Getting the input value on button click.

With the useState() hook we create a state variable (message) to store the current value of the input field. We also create another state variable (updated) that will be updated with the input field value when the button is clicked.

We set an onChange event handler on the input field to make this handler get called whenever the input value changes. In the handler, we use the event.target property to access the object representing the input element. The value property of this object contains the input value, so we pass it to setMessage() to update message, and this reflects on the page.

After setting up the controlled input, we can now use message outside the handleChange handler to access the current value of the input field.

So in the onClick event handler we set on the button, we use setUpdated(message) to update the updated variable with the current input field value.

Get value of uncontrolled input on button click

To get the value of an uncontrolled input on button click in React:

  1. Create a ref for the input field
  2. Set an onClick event handler on the button.
  3. Use the ref object to access the current input value in the event handler.

For example:

App.js

import { useRef, useState } from 'react';

export default function App() {
  const inputRef = useRef(null);

  const [updated, setUpdated] = useState('');

  const handleClick = () => {
    // 👇 "inputRef.current.value" is input value
    setUpdated(inputRef.current.value);
  };

  return (
    <div>
      <input
        ref={inputRef}
        type="text"
        id="message"
        name="message"
      />

      <h2>Updated: {updated}</h2>

      <button onClick={handleClick}>Update</button>
    </div>
  );
}
Updating text with the value of an input field on button click.

While the data in a controlled input is handled by React state, the data in an uncontrolled input is handled by the DOM itself. This is why the input in the example above doesn’t have a value prop or onChange event handler set. Instead, we access the input field value with a React ref. The DOM updates this value when the text in the input is changed.

We create a ref object with the useRef() hook and set it to the ref prop of the input. Doing this sets the current property of the ref object to the DOM object that represents the input element.

useRef() returns a mutable ref object that does not change value when a component is updated. Also, modifying the value of this object’s current property does not cause a re-render. This is in contrast to the setState update function returned from useState().

Although the React documentation recommends using controlled components, uncontrolled components offer some advantages. You might prefer them if the form is very simple and doesn’t need instant validation, and values only need to be accessed when the form is submitted.

How to Link an Image in React

Related: How to Use an Image as a Link in React

To link a local image in React, import the image at the top of the file and assign it to the src prop of an img element.

For example:

App.js

// 👇 import image from file
import myImage from './my-image.jpg';

export default function App() {
  return (
    <div>
      {/* 👇 show image */}
      <img src={myImage} alt="Trees" height="200" />

      <br />

      <span
        style={{
          color: 'green',
          fontSize: '1.2em',
          fontWeight: 'bold',
        }}
      >
        Trees
      </span>
    </div>
  );
}
Linking and displaying an image on the webpage.
Linking and displaying an image on the webpage.

This approach works when using a Webpack-based tool like Create React App.

Note that the image file must be within the project directory to be imported successfully. An error will occur if the file is outside the project directory.

Alternatively, we can use the require() function to link an image in React.

The following code example will produce precisely the same result on the page as the first example.

App.js

export default function App() {
  return (
    <div>
      {/* 👇 */}
      <img
        src={require('./my-image.jpg')}
        alt="Trees"
        height="200"
      />

      <br />
      <span
        style={{
          color: 'green',
          fontSize: '1.2em',
          fontWeight: 'bold',
        }}
      >
        Trees
      </span>
    </div>
  );
}

The advantage require() has here is that it doesn’t need to be at the top of the page. We can simply assign the result of require() to the src prop without having to store it in a variable.

Another way to link an image in React is to place it in the public folder and reference it with its relative path.

For example, if we placed the my-image.png file in the public folder, we’ll be able to display it in the page like this:

App.js

export default function App() {
  return (
    <div>
      {/* 👇 show image */}
      <img src="./my-image.jpg" alt="Trees" height="200" />

      <br />

      <span
        style={{
          color: 'green',
          fontSize: '1.2em',
          fontWeight: 'bold',
        }}
      >
        Trees
      </span>
    </div>
  );
}

Using the public folder is advantageous when we have many images that we want to display dynamically.

In the following examples, we dynamically display 100 images placed in a grid subfolder under public, and named with a certain pattern (image-1.jpg, image-2.jpg, …, image-100.png) in a grid.

App.js

export default function App() {
  return (
    <div>
      <div
        style={{
          display: 'grid',
          gridTemplateColumns:
            'repeat(auto-fit, minmax(min-content, 250px))',
          gap: '8px',
        }}
      >
        {[...Array(100)].map((_, i) => {
          return (
            <div>
              {/* 👇 linking images dynamically */}
              <img
                key={i}
                src={`./grid/image-${i + 1}.jpg`}
                style={{ width: '100%', height: 'auto' }}
              />
            </div>
          );
        })}
      </div>
    </div>
  );
}

If the image is stored online, then we’ll just have to set the URL of the image to the src prop to link and display it, like we do in plain HTML.

App.js

export default function App() {
  return (
    <div>
      {/* 👇 show remote image */}
      <img
        src="http://example.com/trees/my-image.jpg"
        alt="Trees"
        height="200"
      />

      <br />

      <span
        style={{
          color: 'green',
          fontSize: '1.2em',
          fontWeight: 'bold',
        }}
      >
        Trees
      </span>
    </div>
  );
}

3 Easy Ways to Make Any Text Bold in React

To make text bold in React, wrap the text with a span element, and set the fontWeight style property of the span to bold.

For example:

App.js

export default function App() {
  return (
    <div>
      Coding{' '}
      <span style={{ fontWeight: 'bold' }}>Beauty</span>
    </div>
  );
}
Making text bold in React

We used inline styles to make the text bold. The style attribute of a React element accepts a JavaScript object with camelCased properties instead of a CSS kebab-cased string. So, fontWeight sets the font-weight CSS property.

If we don’t need to control the boldness with a condition, then we can just wrap the text with a b element.

App.js

export default function App() {
  return (
    <div>
      Coding <b>Beauty</b>
    </div>
  );
}

Conditionally bold text with inline styles

Sometimes we might want to make a piece of text bold only if a certain condition is true. Here’s how we can do this:

App.js

import { useState } from 'react';

export default function App() {
  const [bold, setBold] = useState(false);

  const handleBoldChange = (event) => {
    setBold(event.target.checked);
  };

  return (
    <div>
      Coding{' '}
      <span
        style={{ fontWeight: bold ? 'bold' : 'normal' }}
      >
        Beauty
      </span>

      <br></br>

      <input
        name="bold"
        type="checkbox"
        value={bold}
        onChange={handleBoldChange}
      ></input>

      <label htmlFor="bold">Bold</label>
    </div>
  );
}
The text is bold only if the checkbox is checked.

We use a state variable named bold to store the current checked state of the checkbox and to determine whether the relevant text should be bold or not.

We attach an event listener to the onChange event, so it is called when the checkbox is checked or unchecked. In this listener, we use the setBold function to update the value of bold and change the boldness of the text.

Bold text with custom component

If we frequently need make text bold, we can abstract the logic into a reusable custom component.

App.js

function BoldText({ children }) {
  return (
    <span style={{ fontWeight: 'bold' }}>{children}</span>
  );
}

export default function App() {
  return (
    <div>
      Coding <BoldText>Beauty</BoldText>
    </div>
  );
}

This code will produce the same result on the web page.

Whatever text is place within the <BoldText> and </BoldText> tags will have a bold font.

Conditionally bold text with custom component

To make text bold conditionally with a custom component, we can create a boolean bold property that will determine whether the child text of the component should be bold or not.

App.js

import { useState } from 'react';

function BoldText({ children, bold }) {
  return (
    <span style={{ fontWeight: bold ? 'bold' : 'normal' }}>
      {children}
    </span>
  );
}

export default function App() {
  const [bold, setBold] = useState(false);

  const handleBoldChange = (event) => {
    setBold(event.target.checked);
  };

  return (
    <div>
      Coding <BoldText bold={bold}>Beauty</BoldText>

      <br></br>

      <input
        name="bold"
        type="checkbox"
        value={bold}
        onChange={handleBoldChange}
      ></input>

      <label htmlFor="bold">Bold</label>
    </div>
  );
}
The text is bold only if the checkbox is checked.

Bold text with class

Alternatively, we can make text bold in React by defining a bold class in a CSS file, e.g., App.css:

App.css

.bold {
  font-weight: bold;
}

We would then import the App.css file and apply the bold class to a span element to make all the text within it bold.

App.js

import './App.css';

export default function App() {
  return (
    <div>
      Coding <span className="bold">Beauty</span>
    </div>
  );
}

And this would produce exactly the same result as the previous two methods:

Conditionally bold text with class

Here’s how we would use a class name to make text bold only if a particular condition is true:

App.js

import { useState } from 'react';
import './App.css';

export default function App() {
  const [bold, setBold] = useState(false);

  const handleBoldChange = (event) => {
    setBold(event.target.checked);
  };

  return (
    <div>
      Coding{' '}
      <span className={bold ? 'bold' : ''}>Beauty</span>

      <br></br>

      <input
        name="bold"
        type="checkbox"
        value={bold}
        onChange={handleBoldChange}
      ></input>
      
      <label htmlFor="bold">Bold</label>
    </div>
  );
}

Using the ternary operator, we set the className property to the bold class if the bold variable is true. Otherwise, we set className to an empty string ('').

The text is bold only if the checkbox is checked.

Tip: Instead of the ternary operator, you can use the clsx utility from NPM to more easily construct class names from a set of conditions in React.

How to Remove an Element On Click in React

In this article, we’ll learn how to easily remove an element onclick in React, whether it’s in a list or it’s a standalone element.

Remove stand-alone element onclick in React

To remove a stand-alone element onclick:

  1. Store the visibility state in a state variable as a Boolean value, and use its value to conditionally render the element.
  2. Attach an event handler to the onClick event of the element.
  3. In the event handler, negate the value of the visibility state to remove the element from the DOM.

One example should make this clear:

import { useState } from 'react';

export default function App() {
  const [visible, setVisible] = useState(true);

  const removeElement = () => {
    setVisible((prev) => !prev);
  };

  return (
    <div>
      Click to remove element
      <br />
      {visible && (
        <button onClick={removeElement}>Remove</button>
      )}
    </div>
  );
}
Removing an element onclick in React

We use the useState() to create a state variable in the component. This hook returns an array of two variables, generally called state and setState. The state variable (visible) holds the current visibility state, and the setState function (setVisible) updates it.

const [visible, setVisible] = useState(true);

We set an event handler to the onClick event of the button, so when the button is clicked, the handler function will be called.

<button onClick={removeElement}>Remove</button>

In the handler function, we use the setState function for the visibility state to update the state.

const removeElement = () => {
  setVisible((prev) => !prev);
};

Instead of passing the negated value directly, we pass a callback function to setState that returns the negated value. This ensures that we always get the most recent state value.

Tip

React batches state changes for performance reasons, so the state may not be updated immediately after setState is called, in the order we might expect. This is why we always pass a function to setState when the new state is computed from the data of the previous state.

Remove element from list onclick

To remove an element from a list onclick:

  1. Attach an event handler to the onClick event of every element in the array representing the list.
  2. In the event handler for a particular element, call the filter() method on the array, specifying a condition that is true for every element in the array apart from the one to be removed.
  3. Use setState to update the state array with the result returned from filter().

For example:

import { useState } from 'react';

export default function App() {
  const [fruits, setFruits] = useState([
    'Orange',
    'Banana',
    'Apple',
  ]);

  const removeElement = (index) => {
    const newFruits = fruits.filter((_, i) => i !== index);
    setFruits(newFruits);
  };

  return (
    <div>
      {fruits.map((fruit, index) => (
        <div key={index}>
          <button
            onClick={() => removeElement(index)}
          >
            {fruit}
          </button>
          <br />
          <br />
        </div>
      ))}
    </div>
  );
}
Removing an element from a list onclick in React
Removing an element from a list onclick

With the map() method, we render a button for each element in the array. For each button, we attach an event handler that will call the removeElement() method, passing as an argument the index of the element that the button represents.

{fruits.map((fruit, index) => (
  <div key={index}>
    <button
      onClick={() => removeElement(index)}
    >
      {fruit}
    </button>
    <br />
    <br />
  </div>
))}

removeElement() removes an element by returning a condition from the filter() callback that is true only for elements in the array that don’t have the index passed to removeIndex(). Doing this excludes the element with that index from the array, so when the array state is updated, the button representing that element is no longer rendered.

const fruits = ['Orange', 'Banana', 'Apple'];

const newFruits = fruits.filter((_, index) => index !== 1);

console.log(newFruits); // [ 'Orange', 'Apple' ]

Note: don’t modify state directly in React

Trying to remove the element from the array by modifying it using a function like splice() will not work:

const removeElement = (index) => {
  // ⚠️ Mutating the array like this will not update the view
  fruits.splice(index, 1);
};

State is meant to be immutable in React, so we can’t update the array by mutating it. It has to be replaced with a new array returned from filter() for the view to update.

Remove object element from list onclick

We can also use this approach to remove an element represented by an object from a list onclick.

import { useState } from 'react';

export default function App() {
  const [fruits, setFruits] = useState([
    { id: 1, name: 'Orange' },
    { id: 2, name: 'Banana' },
    { id: 3, name: 'Apple' },
  ]);

  const removeElement = (id) => {
    const newFruits = fruits.filter(
      (fruit) => fruit.id !== id
    );
    setFruits(newFruits);
  };

  return (
    <div>
      {fruits.map((fruit) => (
        <div key={fruit.id}>
          <button onClick={() => removeElement(fruit.id)}>
            {fruit.name}
          </button>
          <br />
          <br />
        </div>
      ))}
    </div>
  );
}

Instead of filtering by index, this time we filter by the id property to remove an item from the array and remove the element from the list in the DOM.

const fruits = [
  { id: 1, name: 'Orange' },
  { id: 2, name: 'Banana' },
  { id: 3, name: 'Apple' },
];

const newFruits = fruits.filter((fruit) => fruit.id !== 2);

console.log(newFruits);
// [ { id: 1, name: 'Orange' }, { id: 3, name: 'Apple' } ]

How to Use an Async Function in the React useEffect() Hook

In this article, we’ll look at different ways to easily call an async function inside the React useEffect() hook, along with pitfalls to avoid when working with async/await.

Call async Functions With then/catch in useEffect()

async functions perform an asynchronous operation in JavaScript. To wait for the Promise the async function returns to be settled (fulfilled or rejected) in the React useEffect() hook, we could use its then() and catch() methods:

In the following example, we call the fetchBooks() async method to fetch and display stored books in a sample reading app:

export default function App() {
  const [books, setBooks] = useState([]);

  useEffect(() => {
    // await async "fetchBooks()" function
    fetchBooks()
      .then((books) => {
        setBooks(books);
      })
      .catch(() => {
        console.log('Error occured when fetching books');
      });
  }, []);

  return (
    <div>
      {books.map((book) => (
        <div>
          <h2>{book.title}</h2>
        </div>
      ))}
    </div>
  );
}

async/await Problem: async Callbacks Can’t Be Passed to useEffect()

Perhaps you would prefer to use the async/await syntax in place of then/catch. You might try doing this by making the callback passed to useEffect() async.

This isn’t a good idea though, and if you’re using a linter it will inform you of this right away.

// ❌ Your linter: don't do this!
useEffect(async () => {
  try {
    const books = await fetchBooks();
    setBooks(books);
  } catch {
    console.log('Error occured when fetching books');
  }
}, []);

Your linter complains because the first argument of useEffect() is supposed to be a function that either returns nothing or returns a function to clean up side effects. But async functions always return a Promise (implicitly or explicitly), and Promise objects can’t be called as functions. This could cause real issues in your React app, such as memory leaks.

useEffect(async () => {
  const observer = () => {
    // do stuff
  };

  await fetchData();

  observable.subscribe(observer);

  // Memory leak!
  return () => {
    observable.unsubscribe(observer);
  };
}, []);

In this example, because the callback function is async, it doesn’t actually return the defined clean-up function, but rather a Promise object that is resolved with the clean-up function. Hence, this clean-up function is never called, and the observer is never unsubscribed from the observable, resulting in a memory leak.

So how can we fix this? How can we use the await operator with an async function in the useEffect() hook?

async/await Solution 1: Call async Function in IIFE

One straightforward wait to solve this problem is to await the async function in an immediately invoked function expression (IIFE):

const [books, setBooks] = useState([]);

useEffect(() => {
  (async () => {
    try {
      const books = await fetchBooks();
      setBooks(books);
    } catch (err) {
      console.log('Error occured when fetching books');
    }
  })();
}, []);

As the name suggests, an IIFE is a function that runs as soon as it is defined. They are used to avoid polluting the global namespace and in scenarios where trying an await call could cause problems in the scope containing the IIFE (e.g., in the useEffect() hook, or in the top-level scope for pre-ES13 JavaScript).

async/await Solution 2: Call async Function in Named Function

Alternatively, you can await the async function inside a named function:

useEffect(() => {

  // Named function "getBooks"
  async function getBooks() {
    try {
      const books = await fetchBooks();
      setBooks(books);
    } catch (err) {
      console.log('Error occured when fetching books');
    }
  }

  // Call named function
  getBooks();
}, []);

Remember the example using the observable pattern? Here’s how we can use a named async function to prevent the memory leak that occurred:

// ✅ Callback is not async
useEffect(() => {
  const observer = () => {
    // do stuff
  };

  // Named function "fetchDataAndSubscribe"
  async function fetchDataAndSubscribe() {
    await fetchData();
    observable.subscribe(observer);
  }

  fetchDataAndSubscribe();

  // ✅ No memory leak
  return () => {
    observable.unsubscribe(observer);
  };
}, []);

async/await Solution 3: Create Custom Hook

We can also create a custom hook that behaves similarly to useEffect() and can accept an async callback without causing any issues.

The custom hook could be defined this way:

export function useEffectAsync(effect, inputs) {
  useEffect(() => {
    return effect();
  }, inputs);
}

And we’ll be able to call it from multiple places in our code like this:

const [books, setBooks] = useState([]);

useEffectAsync(async () => {
  try {
    const books = await fetchBooks();
    setBooks(books);
  } catch (err) {
    console.log('Error occured when fetching books');
  }
});

With these three approaches, we can now easily use the await operator with async functions in the useEffect() hook.

Define Async Function Outside useEffect()

To define a named async function outside the useEffect() hook, you can wrap the function with the useCallback() hook:

const getBooks = useCallback(async () => {
  try {
    const books = await fetchBooks();
    setBooks(books);
  } catch (err) {
    console.log('Error occured when fetching books');
  }
}, []);

useEffect(() => {
  getBooks();
}, [getBooks]);

Without useCallback(), the getBooks() function will be re-created on every re-render, triggering useEffect() and causing performance problems.

How to Use Async / Await in the React useEffect() Hook

To await an async function in the React useEffect() hook, wrap the async function in an immediately invoked function expression (IIFE).

For example:

const [books, setBooks] = useState([]);

useEffect(() => {
  (async () => {
    try {
      // await async "fetchBooks()" function
      const books = await fetchBooks();
      setBooks(books);
    } catch (err) {
      console.log('Error occured when fetching books');
    }
  })();
}, []);

In this article, we’ll look at different ways to call an async function in the useEffect() hook, along with pitfalls to avoid when working with async/await.

Calling async Functions With then/catch in useEffect()

async functions perform an asynchronous operation in JavaScript. To wait for the Promise the async function returns to be settled (fulfilled or rejected) in the React useEffect() hook, we could use its then() and catch() methods:

In the following example, we call the fetchBooks() async method to fetch and display stored books in a sample reading app:

export default function App() {
  const [books, setBooks] = useState([]);

  useEffect(() => {
    // await async "fetchBooks()" function
    fetchBooks()
      .then((books) => {
        setBooks(books);
      })
      .catch(() => {
        console.log('Error occured when fetching books');
      });
  }, []);

  return (
    <div>
      {books.map((book) => (
        <div>
          <h2>{book.title}</h2>
        </div>
      ))}
    </div>
  );
}

async/await Problem: async Callbacks Can’t Be Passed to useEffect()

Perhaps you would prefer to use the async/await syntax in place of then/catch. You might try doing this by making the callback passed to useEffect() async.

This isn’t a good idea though, and if you’re using a linter it will inform you of this right away.


// ❌ Your linter: don't do this!
useEffect(async () => {
  try {
    const books = await fetchBooks();
    setBooks(books);
  } catch {
    console.log('Error occured when fetching books');
  }
}, []);

Your linter complains because the first argument of useEffect() is supposed to be a function that either returns nothing or returns a function to clean up side effects. But async functions always return a Promise (implicitly or explicitly), and Promise objects can’t be called as functions. This could cause real issues in your React app, such as memory leaks.


useEffect(async () => {
  const observer = () => {
    // do stuff
  };

  await fetchData();

  observable.subscribe(observer);

  // Memory leak!
  return () => {
    observable.unsubscribe(observer);
  };
}, []);

In this example, because the callback function is async, it doesn’t actually return the defined clean-up function, but rather a Promise object that is resolved with the clean-up function. Hence, this clean-up function is never called, and the observer never unsubscribed from the observable, resulting in a memory leak.

So how can we fix this? How can we use the await operator with an async function in the useEffect() hook?

async/await Solution 1: Call async Function in IIFE

One straightforward way to solve this problem is to await the async function in an immediately invoked function expression (IIFE):


const [books, setBooks] = useState([]);

useEffect(() => {
  (async () => {
    try {
      const books = await fetchBooks();
      setBooks(books);
    } catch (err) {
      console.log('Error occured when fetching books');
    }
  })();
}, []);

As the name suggests, an IIFE is a function that runs as soon as it is defined. They are used to avoid polluting the global namespace and in scenarios where trying an await call could cause problems in the scope containing the IIFE (e.g., in the useEffect() hook).

async/await Solution 2: Call async Function in Named Function

Alternatively, you can await the async function inside a named function:

useEffect(() => {

  // Named function "getBooks"
  async function getBooks() {
    try {
      const books = await fetchBooks();
      setBooks(books);
    } catch (err) {
      console.log('Error occured when fetching books');
    }
  }

  // Call named function
  getBooks();
}, []);

Remember the example using the observable pattern? Here’s how we can use a named async function to prevent the memory leak that occurred:

// ✅ Callback is not async
useEffect(() => {
  const observer = () => {
    // do stuff
  };

  // Named function "fetchDataAndSubscribe"
  async function fetchDataAndSubscribe() {
    await fetchData();
    observable.subscribe(observer);
  }

  fetchDataAndSubscribe();

  // ✅ No memory leak
  return () => {
    observable.unsubscribe(observer);
  };
}, []);

async/await Solution 3: Create Custom Hook

We can also create a custom hook that behaves similarly to useEffect() and can accept an async callback without causing any issues.

The custom hook could be defined this way:

export function useEffectAsync(effect, inputs) {
  useEffect(() => {
    return effect();
  }, inputs);
}

And we’ll be able to call it from multiple places in our code like this:

const [books, setBooks] = useState([]);

useEffectAsync(async () => {
  try {
    const books = await fetchBooks();
    setBooks(books);
  } catch (err) {
    console.log('Error occured when fetching books');
  }
});

With these three approaches, we can now easily use the await operator with async functions in the useEffect() hook.

How to Remove an Item from a State Array in React

In this article, we’re going to learn how to easily remove an item from a state array in React.

The Array filter() Method

To remove an item from a state array in React, call the filter() method on the array, specifying a test that every item in the array apart from the one to be removed will pass, then update the state with the result of filter() with setState.

import { useState } from 'react';

export default function App() {
  const initialState = [
    { id: 1, name: 'Banana', amount: 5 },
    { id: 2, name: 'Apple', amount: 6 },
  ];

  const removeSecond = () => {
    setFruits((current) =>
      current.filter((fruit) => fruit.id !== 2)
    );
  };

  const [fruits, setFruits] = useState(initialState);

  return (
    <div style={{ margin: '16px' }}>
      <button onClick={removeSecond}>Remove second</button>
      {fruits.map((fruit) => (
        <div key={fruit.id}>
          <h2>Name: {fruit.name}</h2>
          <h2>Amount: {fruit.amount}</h2>
          <hr />
        </div>
      ))}
    </div>
  );
}
Removing an item from a state array in React.

We remove the fruit object with the id 2 by returning a condition from the filter() callback that is true only for the items in the array that don’t have an id of 2. Doing this excludes the target item from the array returned from filter().

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
];

const secondRemoved = initialState.filter((fruit) => fruit.id !== 2);

// [ { id: 1, name: 'Banana', amount: 5 } ]
console.log(secondRemoved);

Since App here is a functional component, we use the useState() React hook to create the initial state array. The first value useState() returns lets us access the state data. The second value is a function used to update the state (generically called setState). We pass a function to setState (named setFruits here) to ensure that we get the current/latest state.

const removeSecond = () => {
  // "current" contains the latest state array
  setFruits((current) =>
    current.filter((fruit) => fruit.id !== 2)
  );
};

Tip: Always pass a function to setState when the new state is computed from the current state data.

Don’t Modify State Directly in React

Note that trying to remove the item from the array by modifying it directly using a function like splice() will not work:

const removeSecond = () => {
  // Find the index of the object to be removed
  const secondIndex = fruits.findIndex((fruit) => fruit.id === 2);

  // Mutating the array like this will not update the view
  fruits.splice(secondIndex, 1);
};

State is meant to be immutable in React, so we can’t update the array by mutating it. It has to be replaced with a new array returned from filter() for the view to update.

Remove Items from a State Array Based on Multiple Conditions

If you need to remove an item from the state array based on multiple conditions, you can use the logical AND (&&) or logical OR (&&) operator.

Using the Logical OR (||) Operator

Here is an example of using the logical OR (||) operator to remove an item from a state array.

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
  { id: 3, name: 'Orange', amount: 10 },
  { id: 4, name: 'Watermelon', amount: 1 },
];

const [fruits, setFruits] = useState(initialState);

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) =>
        fruit.name === 'Orange' || fruit.name === 'Apple'
    )
  );
};

Combining a set of operands with the || operator will result in true if at least one of the operands evaluates to true. By using this operator with the filter() method, we return a new array containing only the fruit objects with a name equal to 'Orange' or 'Apple'.

Using the Logical AND (&&) Operator

Here is an example of using the logical AND (&&) operator to remove an item from a state array:

const initialState = [
  { id: 1, name: 'Banana', amount: 5 },
  { id: 2, name: 'Apple', amount: 6 },
  { id: 3, name: 'Orange', amount: 10 },
  { id: 4, name: 'Watermelon', amount: 1 },
];

const [fruits, setFruits] = useState(initialState);

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) => fruit.id !== 2 && fruit.id !== 4
    )
  );
};

Combining operands with the && operator will result in true only if all the operands are true.

By combining the filter() method with the && operator, we are able to specify a compound boolean expression that removes the fruit objects with ids of 2 and 4.

Simplifying Compound Boolean Expressions with De Morgan’s Laws

We can use one of De Morgan’s laws to convert the AND condition from our previous example to an OR condition and reduce the number of negations.

const remove = () => {
  setFruits((current) =>
    current.filter(
      (fruit) => !(fruit.id === 2 || fruit.id === 4)
    )
  );
};

This transformation could make the expression easier to read and understand.

How to Quickly Use a Button as a Link in React

To use a button as a link in React, wrap the button in an anchor (<a>) element. Clicking a link button will make the browser navigate to the specified URL.

JavaScript
export default function MyComponent() { return ( <div> <a href="/posts"> <button>Posts</button> </a> </div> ); }

If you’re using React Router, then wrap the button in the Link component instead, to make the browser navigate to the specified route without refreshing the page when the button is clicked.

JavaScript
import { Link } from 'react-router-dom'; export default function MyComponent() { return ( <div> <Link to="/posts"> <button>Posts</button> </Link> </div> ); }

The react-router-dom Link component renders an anchor element, so it works similarly to the first example.

We can also use custom button components as links by wrapping them with an anchor element or Link component. For example:

JavaScript
import { Link } from 'react-router-dom'; function MyCustomButton({ children }) { return <button>{children}</button>; } export default function MyComponent() { return ( <div> <Link to="/posts"> <MyCustomButton>Posts</MyCustomButton> </Link> </div> ); }

When using Material UI, we can specify a link for the Button component using the href prop.

JavaScript
import { Button } from '@mui/material'; export default function MyComponent() { return ( <div> <Button href="/posts">Posts</Button> </div> ); }

To use as a React Router Link, we can use the component prop of the Button.

JavaScript
import { Button } from '@mui/material'; import { Link } from 'react-router-dom'; export default function MyComponent() { return ( <div> <Button component={Link} to="/posts"> Posts </Button> </div> ); }

Other Material UI components like IconButton also have a component prop. Setting this prop is useful when we want the button component to inherit its color from its parent.

In this scenario, if we wrap the component with a Link, it will inherit its color from the Link instead of the intended parent. For example:

JavaScript
import { IconButton, Box, Typography } from '@mui/material'; import { Link } from 'react-router-dom'; import { Photo } from '@mui/icons-material'; export default function MyComponent() { return ( // We want the IconButton to inherit its parent color (white) <Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}> <Typography>Lorem Ipsum</Typography> {/* But this wrapping makes it inherit from this Link */} <Link to="/photos"> <IconButton color="inherit"> <Photo /> </IconButton> </Link> </Box> ); }
The IconButton inherits its color from the Link(blue) instead of the Box (white).
The IconButton inherits its color from the Link (blue) instead of the Box (white).

We can fix this issue by setting the component prop to a Link instead of wrapping:

JavaScript
import { IconButton, Box, Typography } from '@mui/material'; import { Link } from 'react-router-dom'; import { Photo } from '@mui/icons-material'; export default function MyComponent() { return ( <Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}> <Typography>Lorem Ipsum</Typography> {/* Setting the "component" prop to a "Link" component */} <IconButton component={Link} to="/photos" color="inherit"> <Photo /> </IconButton> </Box> ); }
The IconButton inherits its color from the Box.
The IconButton inherits its color from the Box.