简体   繁体   中英

React Bootstrap dropdown with filter doesn't work on mapped data

I'm using the react-bootstrap library in a project, and have used the <Dropdown /> component, and I'm trying to get it to include a filterable search. I've got this from the docs:

import React, { useState } from 'react';
import Dropdown from 'react-bootstrap/Dropdown';
import Form from 'react-bootstrap/Form';

// The forwardRef is important!!
// Dropdown needs access to the DOM node in order to position the Menu
const CustomToggle = React.forwardRef(({ children, onClick }, ref) => (
  <a
    href=""
    ref={ref}
    onClick={(e) => {
      e.preventDefault();
      onClick(e);
    }}
  >
    {children}
    &#x25bc;
  </a>
));

// forwardRef again here!
// Dropdown needs access to the DOM of the Menu to measure it
const CustomMenu = React.forwardRef(
  ({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
    const [value, setValue] = useState('');

    return (
      <div
        ref={ref}
        style={style}
        className={className}
        aria-labelledby={labeledBy}
      >
        <Form.Control
          autoFocus
          className="mx-3 my-2 w-auto"
          placeholder="Type to filter..."
          onChange={(e) => setValue(e.target.value)}
          value={value}
        />
        <ul className="list-unstyled">
          {React.Children.toArray(children).filter(
            (child) =>
              !value || child.props.children.toLowerCase().startsWith(value),
          )}
        </ul>
      </div>
    );
  },
);

render(
  <Dropdown>
    <Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components">
      Custom toggle
    </Dropdown.Toggle>

    <Dropdown.Menu as={CustomMenu}>
      <Dropdown.Item eventKey="1">Red</Dropdown.Item>
      <Dropdown.Item eventKey="2">Blue</Dropdown.Item>
      <Dropdown.Item eventKey="3" active>
        Orange
      </Dropdown.Item>
      <Dropdown.Item eventKey="1">Red-Orange</Dropdown.Item>
    </Dropdown.Menu>
  </Dropdown>,
);

And with the default data it works, but if I replace it with some data which I map over:

                        <Dropdown className="mb-2">
                          <Dropdown.Toggle
                            className="form-control"
                            as={CustomToggle}
                            id="dropdown-custom-components"
                          >
                            Search for contact...
                          </Dropdown.Toggle>

                          <Dropdown.Menu as={CustomMenu}>
                            {allContacts.map((contact, key) => {
                              return (
                                <Dropdown.Item
                                  key={key}
                                  value={contact.name}
                                  onClick={(e) => {
                                    console.log(e);
                                    setSelectedContact(contact);
                                  }}
                                >
                                  {contact.name} - {contact.outlet}
                                </Dropdown.Item>
                              );
                            })}
                          </Dropdown.Menu>
                        </Dropdown>

It displays the data in the dropdown but if I try and search for something I get an error: Objects are not valid as a React child (found: object with keys {map, forEach, count, toArray, only}). If you meant to render a collection of children, use an array instead. Objects are not valid as a React child (found: object with keys {map, forEach, count, toArray, only}). If you meant to render a collection of children, use an array instead. and this confused me because the data I'm mapping over ( allContacts ) is already an array, but it is an array of objects, if that makes a difference?

I'd appreciate any pointers, thank you

Just in case anyone else has the same problem, I've managed to solve it for me.

If I don't pass the key prop in the map() function, and instead use the UID of the contact, and remove the value attribute, it then works

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM