resolving error message "react-dom.development.js:4091 Uncaught TypeError: onItemSelect is not a function"

Viewed 841

I don't know why but I get this error constantly when I change the option in the selector ."react-dom.development.js:4091 Uncaught TypeError: onItemSelect is not a function" :(

    import React from "react";
    import Product from "./Product";
    import ListGroup from "./listGroup";
    
    export default function Main(props) {
      const { products, onAdd, categories } = props;
    
        const handleCategorySelect = () => {
        console.log("Click");
      };
    
      return (
        <main className="block col-2">
          <ListGroup items={categories} />
          <h2>Products</h2>
          <div>
            {products.map((product) => (
              <Product
                key={product.id}
                product={product}
                onAdd={onAdd}
                onItemSelect={handleCategorySelect}
              ></Product>
            ))}
          </div>
        </main>
      );
    }

and my listGroup.jsx is :

import React from "react";

function ListGroup(props) {
  const { items, onItemSelect } = props;
  return (
    <form>
      <select
        value=""
        id="category"
        name="category"
        onChange={() => onItemSelect()}
      >
        <option hidden value="">
          Choose here
        </option>
        {items.map((item) => (
          <option key={item._id}>{item.name}</option>
        ))}
      </select>
    </form>
  );
}

export default ListGroup;

and also how can I pass the item object to onChange ? I mean if it was a list group I would go with :

<ul className="list-group">
  {items.map(item => (
    <li
      onClick={() => onItemSelect(item)}
      key={item[valueProperty]}
      className={
        item === selectedItem ? "list-group-item active" : "list-group-item"
      }
    >
      {item[textProperty]}
    </li>
  ))}
</ul>

but with select and option I don't know How to do it.

1 Answers

It is because you didn't pass the function to the ListGroup component

export default function Main(props) {
...
  <ListGroup items={categories} />

But you call it on change

function ListGroup(props) {
...
      <select
        value=""
        id="category"
        name="category"
        onChange={() => onItemSelect()}
      >

Try this

<ListGroup items={categories} onItemSelect={handleCategorySelect} />

And here is how you can pass the value of the select back to the parent component:

function ListGroup({ items, onItemSelect }) {
  function handleItemChange(e) {
    onItemSelect(e.target.value);
  }
  
  return (
    <div>
      <select onChange={handleItemChange}>
        {items.map((item) => <option key={item.name}>{item.name}</option>)}
      </select>
    </div>
  );
}

function Main() {
  const items = [
    { name: 'apple' },
    { name: 'milk' },
    { name: 'bread' },
    { name: 'cheese' }
  ];
  
  function handleListSelect(val) {
    console.log(`I selected ${val}`);
  }
  
  return (
    <div>
      <ListGroup items={items} onItemSelect={handleListSelect} />
    </div>
  );
}

function App() {
  return (
    <div>
      <Main />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>

Related