0

So here I have search functionality. Everything works fine except when an Item has not been found in the array. I have tried something with objects.Keys but it is displaying it on the render not when the Book has not been found like it should. Should I use if statement or.

import React,{useState, useEffect, useRef, useContext}from 'react'
import {FaSearch} from 'react-icons/fa'
import { 
    Link, useHistory
  } from "react-router-dom";
import { BookContext } from '../../context/books';
import SearchBooks from './SearchBooks';

const Search = () => {

  const {data}= useContext(BookContext)
  const [searchValue, setSearchValue] = React.useState('');
  const history= useHistory()
  const ref=useRef()

  function filterBooks(book) {
    console.log(book);
    if (!searchValue.length  ) return false;
    return book.bookName?.toLowerCase().includes(searchValue.toLowerCase());
  }

  const handleSearch = (e) => {
    if (ref.current && !ref.current.contains(e.target)) {
     setSearchValue('')
    }
  };
     
  useEffect(() => {
    document.addEventListener('click', handleSearch);
    return () => {
      document.removeEventListener('click', handleSearch);
    };
  }, []);
  

  
        return (
        <div className='search__cont' ref={ref}>   
              {Object.keys(data).filter(filterBooks).length === 0 &&(
           <div>
             <h3>Book not found</h3>
             </div>
         )}
           <SearchBooks searchValue={searchValue} setSearchValue={setSearchValue }/>          
           {Object.keys(data)
             .map((key) => data[key])
             .reduce((acc, curr) => acc.concat(curr), [])
             .filter(filterBooks)
             .map((book) => {          
             return (
             <>       
              <div  className='search__books'
                onClick={() => {
                  history.push("/book/id", { book }); setSearchValue('')
                }}
               >            
                {" "}
                {book.bookName}{" "}
              </div>            
            </>
          );
        })}
           </div>
    )
}

export default Search
3
  • If you think this I forgot to remove it if(!searchValue.length ) return book.bookName > 10 .Thats my attempt that you shoved. I know that's the error Commented Apr 4, 2021 at 22:19
  • The issue is this. it is not displaying "no book has been found" when the search value is not found. I have like 10 components connected to each other. so Creating the sandbox would take me at least 20 min. If you don't know you don't know Commented Apr 4, 2021 at 22:36
  • codesandbox.io/s/affectionate-pine-pbchq?file=/src/Search.js Commented Apr 4, 2021 at 22:55

1 Answer 1

1

You're filtering the category names instead of the books (data is an object with category names as keys and books as values). You can use Object.values and Array.prototype.flat to get an array of all the books and then apply the filter.

const filteredBooks = Object.values(data).flat().filter(filterBooks)
const searchQueryPresent = searchValue.trim().length > 0
{
  searchQueryPresent &&
    (filteredBooks.length === 0 ? (
      <div>No books found</div>
    ) : (
      filteredBooks.map((book) => {
        return <>{/* render books */}</>
      })
    ))
}

Edit on CodeSandbox

Sign up to request clarification or add additional context in comments.

4 Comments

filterBooks is return false so that means, that items are not shown on first the render like I want. but in your case is true. So that means when It's false I see book not found on the first render not when an item is not found
@mura1 You can render the book list or the "no books found" message only if the search query is present. Just updated my answer and the linked CodeSandbox.
Thank you. I know this not the question, but how would I lower the number of search values let's say to a max to 10. Right now If I type A word it is displaying a bunch of them
@mura1 You can use Array.prototype.slice to return a slice of the array. Just updated the CodeSandbox to give you an idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.