---
id: 67ff838da1cb2927ae18a3f5
title: Step 24
challengeType: 0
dashedName: step-24
---

# --description--

`useMemo()` takes two arguments: a function that returns the value you want to memoize, and an array of dependencies. The memoized value will only be recomputed when one or more of its dependencies change.

Here's the basic syntax for `useMemo()`:

```js
const memoizedValue = useMemo(() => {
  // Some expensive calculation
  return value;
}, [dependency1, dependency2]);
```

Set `filteredItems` equal to `useMemo()`, and pass it an anonymous function with curly braces. Inside the curly braces, use a `return` statement to explicitly return your existing filtering logic. Also, add `query` as the only dependency in the dependencies array. This ensures that the filtering operation is only re-run when `query` changes.

# --hints--

You should set `filteredItems` equal to calling the `useMemo()` hook.

```js
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src ===  "index.jsx").innerText;
const exports = {};
const a = eval(script);
const shoppingListString = exports.ShoppingList.toString();

assert.match(shoppingListString, /var\s*filteredItems\s*=\s*useMemo\s*\(/);
```

You should pass an anonymous function to `useMemo()` with curly braces.

```js
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src ===  "index.jsx").innerText;
const exports = {};
const a = eval(script);
const shoppingListString = exports.ShoppingList.toString();

assert.match(shoppingListString, /var\s*filteredItems\s*=\s*useMemo\s*\(\s*function\s*\(\s*\)\s*{/);
```

You should use a `return` statement to explicitly return your existing filtering logic.

```js
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src ===  "index.jsx").innerText;
const exports = {};
const a = eval(script);
const shoppingListString = exports.ShoppingList.toString();

assert.match(shoppingListString, /var\s*filteredItems\s*=\s*useMemo\s*\(\s*function\s*\(\s*\)\s*{\s*return\s+items\.filter\s*\(function\s*\(\s*item\s*\)\s*{\s*return\s+item\.toLowerCase\(\s*\).includes\(\s*query\.toLowerCase\(\s*\)\s*\);?\s*}\s*\);?\s*}/);
```

You should add `query` as the only dependency in the dependencies array.

```js
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src ===  "index.jsx").innerText;
const exports = {};
const a = eval(script);
const shoppingListString = exports.ShoppingList.toString();

assert.match(shoppingListString, /var\s*filteredItems\s*=\s*useMemo\s*\(\s*function\s*\(\s*\)\s*{(.|\n)*},\s*\[\s*query\s*\]\s*\);?/);
```

# --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
const { useState, useMemo } = React;

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...");
  --fcc-editable-region--
  const filteredItems = items.filter((item) => 
    item.toLowerCase().includes(query.toLowerCase())
  );
  --fcc-editable-region--

  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>
  );
};

```
