0

Hi I am creating an app where the user can search for books by title. The user can search and each book result has a dropdown. so I have many dropdowns on a single page (the search results page). I am trying to make a dropdown close when the user clicks outside of the dropdown button (which is a div). Currently I can open the dropdown by clicking on the dropdown button and only close it when clicking on the dropdown button again. I need the dropdown to close when clicking anywhere except the dropdown options. How would I go about doing this?

ButtonDropDown.js

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { BsFillCaretDownFill } from 'react-icons/bs';

const ButtonDropDown = ({ choices, label }) => {
  const [active, setActive] = useState(false);

  const toggleClass = () => {
    setActive(!active);
  };

  return (
    <div className="dropdown">
      <button onClick={toggleClass} type="button" className="dropbtn">
        <BsFillCaretDownFill />
      </button>
      <div
        id="myDropdown"
        className={`dropdown-content ${active ? `show` : `hide`}`}
      >
        <div>{label}</div>
        {choices.map((choice) => (
          <div>{choice}</div>
        ))}
      </div>
    </div>
  );
};

ButtonDropDown.propTypes = {
  choices: PropTypes.arrayOf(PropTypes.string).isRequired,
  label: PropTypes.string,
};

ButtonDropDown.defaultProps = {
  label: 'Move to...',
};

export default ButtonDropDown;

Book.js

import React from 'react';
import PropTypes from 'prop-types';
import ButtonDropDown from './ButtonDropDown';

const Book = ({ title, authors, thumbnail }) => {
  return (
    <div className="book">
      <img src={thumbnail} alt={title} className="book-thumbnail" />
      <div className="book-title">{title}</div>
      <div className="book-authors">{authors}</div>
      <ButtonDropDown
        choices={['Currently Reading', 'Want to Read', 'Read', 'None']}
      />
    </div>
  );
};
// Move to..., currently reading, want to read, read, none

Book.propTypes = {
  thumbnail: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  authors: PropTypes.arrayOf(PropTypes.string),
};

Book.defaultProps = {
  authors: [],
};

export default Book;

SearchPage.js

import React, { useEffect, useState } from 'react';
import { BsArrowLeftShort } from 'react-icons/bs';
// import { debounce } from 'debounce';
import SearchBar from '../components/SearchBar';
import { search } from '../api/BooksAPI';
import Book from '../components/Book';

const SearchPage = () => {
  const [query, setQuery] = useState('');
  const [data, setData] = useState([]);
  // const [isLoading, setIsLoading] = useState(true);

  const handleChange = (e) => {
    setQuery(e.target.value);
  };

  useEffect(() => {
    const bookSearch = setTimeout(() => {
      if (query.length > 0) {
        search(query).then((res) => {
          if (res.length > 0) {
            setData(res);
          } else setData([]);
        });
      } else {
        setData([]); // make sure data is not undefined
      }
    }, 1000);
    // bookSearch();
    // console.log(data); // undefined initially since we didnt search anything
    return () => clearTimeout(bookSearch);
    // if (data !== []) setIsLoading(false);
    // setIsLoading(true);
  }, [query]);

  return (
    <div>
      <SearchBar
        type="text"
        searchValue={query}
        placeholder="Search for a book"
        icon={<BsArrowLeftShort />}
        handleChange={handleChange}
      />
      <div className="book-list">
        {data !== []
          ? data.map((book) => (
              <Book
                key={book.id}
                title={book.title}
                authors={book.authors}
                thumbnail={book.imageLinks.thumbnail}
              />
            ))
          : 'ok'}
      </div>
    </div>
  );
};

export default SearchPage;
alti21
  • 127
  • 2
  • 11

0 Answers0