---
id: 67ff7500255008598207a70c
title: Step 23
challengeType: 0
dashedName: step-23
---

# --description--

Now you will see `Filtering items...` in the console every time you type in the search bar and check or uncheck an item. This is because those actions update the state of the component, which causes it to re-render.

This isn't usually a problem. But if you have a lot of items in the list, or if you're fetching a lot of data from an API and manipulating it, your app can feel slow.

To improve performance, you can use the `useMemo()` hook to memoize, or in other words, cache, the result of the filtering operation. Then, React will only re-run the filtering operation when its dependency changes, rather than on every render.

First, destructure the `useMemo()` hook from React at the top of your file.

# --hints--

You should destructure `useMemo` from `React` at the top of the file. Make sure you aren't removing the `useState` hook you're already using.

```js
assert.match(code, /(const|let|var)\s*{[^}]*\buse(State|Memo)\b[^}]*\buse(Memo|State)\b[^}]*}\s*=\s*React/);
```

# --seed--

## --seed-contents--

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Shopping List</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <main id="app-container"></main>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { ShoppingList } from "./index.jsx";
      const appContainer = document.getElementById("app-container");
      const root = ReactDOM.createRoot(appContainer);
      root.render(<ShoppingList />);
    </script>
  </body>
</html>

```

```css
:root {
  --dark-grey: #1b1b32;
  --light-grey: #f5f6f7;
  --dark-orange: #f89808;
  --yellow: #f1be32;
  --golden-yellow: #feac32;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  line-height: 1.5;
  color: var(--dark-grey);
  background-color: var(--dark-grey);
}

main,
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container {
  background-color: var(--light-grey);
  width: 90%;
  margin: 20px;
  padding: 10px;
}

h1 {
  color: var(--dark-grey);
}

form {
  text-align: center;
}

button {
  cursor: pointer;
}

button {
  cursor: pointer;
  width: 100px;
  margin: 3px;
  color: var(--dark-grey);
  background-color: var(--golden-yellow);
  background-image: linear-gradient(#fecc4c, #ffac33);
  border-color: var(--golden-yellow);
  border-width: 3px;
}

button:hover {
  background-image: linear-gradient(#ffcc4c, #f89808);
}

input {
  color: var(--dark-grey);
  margin-left: 5px;
  padding: 3px;
}

li {
  text-align: left;
  margin: 10px 0;
}

.selected-item {
  font-weight: bold;
}

@media (min-width: 425px) {
  .container {
    width: 400px;
  }
}

```

```jsx
--fcc-editable-region--
const { useState } = React;
--fcc-editable-region--

const items = [
  "Apples",
  "Bananas",
  "Strawberries",
  "Blueberries",
  "Mangoes",
  "Pineapple",
  "Lettuce",
  "Broccoli",
  "Paper Towels",
  "Dish Soap",
];

export const ShoppingList = () => {
  const [query, setQuery] = useState("");
  const [selectedItems, setSelectedItems] = useState([]);

  console.log("Filtering items...");
  const filteredItems = items.filter((item) => 
    item.toLowerCase().includes(query.toLowerCase())
  );

  const toggleItem = (item) => {
    setSelectedItems((prev) =>
      prev.includes(item) ? prev.filter((i) => i !== item) : [...prev, item]
    );
  };

  return (
    <div className="container">
      <h1>Shopping List</h1>
      <form>
        <label htmlFor="search">Search for an item:</label>
        <input
          id="search"
          type="search"
          placeholder="Search..."
          aria-describedby="search-description"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
        /> 
        <p id="search-description">Type to filter the list below:</p>
        <ul>
          {filteredItems.map((item) => {
            const isChecked = selectedItems.includes(item);
            return (
              <li
                key={item}
                style={{ textDecoration: isChecked ? "line-through" : "none" }}
              >
                <label>
                  <input
                    type="checkbox"
                    onChange={() => toggleItem(item)}
                    checked={isChecked}
                  />
                  {item}
                </label>
              </li>
            );
          })}
        </ul>
      </form>
    </div>
  );
};
```
