6

Add a Simple Search Function to React App without a Server

 3 years ago
source link: https://blog.bitsrc.io/add-a-simple-search-function-to-react-app-without-a-server-22deda8966cd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Add a Simple Search Function to React App without a Server

Image for post
Image for post
Serverless React search with Fuse.js

The search function is one of the most important features of a software application. Search sites like Google and DuckDuckGo have helped millions of users to navigate through the internet and quickly find what they’re looking for in mere seconds.

You may find that you need to include a search function into your React application, but you don’t want to set up a dedicated server just to handle the search. Is there a way to add a simple search into a React application?

Yes, there is. Fuse.js is a powerful and light-weight search library that’s built to handle search within the front-end. The library uses a technique known as fuzzy searching, which find strings that are approximately equal to a given pattern rather than just the exact matches.

The fuzzy search method is great because your application will be able to return a set of close matches even when the search pattern has any wrong spelling or word order in a sentence.

What you will build

This tutorial will help you to build a simple React application that has its search function powered by Fuse.js. The application will serve a curated list of awesome books for software developers that you can filter with the search function.

Here’s what the end result looks like:

Image for post
Image for post
My favorite books. Great for software developers too

I’ve shared my demo project, as well as its components, on Bit.dev. Use it to examine it and even install its components in your own project.

To get started, you need to bootstrap a new React application by using Create React App:

npx create-react-app react-fusejs-example

Once finished, let’s start by writing the books data as an array of objects. You will pass this data to the application and render it as a list of cards:

Image for post
Image for post
Building a list of books

Create a new file named books.json and create your list of books. The data will have the following properties:

  • title string for the book title
  • author string for the author
  • image string for the book image src attribute
  • url for the link to purchase the book or review

Here’s my file if you want to copy it:

[
{
"title": "Steve Jobs",
"image": "https://images-na.ssl-images-amazon.com/images/I/41dKkez-1rL._SX326_BO1,204,203,200_.jpg",
"author": "Walter Isaacson",
"url": "https://www.amazon.com/Steve-Jobs-Walter-Isaacson/dp/1451648537"
},
{
"title": "Zero to One",
"image": "https://images-na.ssl-images-amazon.com/images/I/4137OkbPQ4L._SX331_BO1,204,203,200_.jpg",
"author": "Peter Thiel, Blake Masters",
"url": "https://www.amazon.com/Zero-One-Notes-Startups-Future/dp/0804139296"
},
{
"title": "The Pragmatic Programmer",
"image": "https://images-na.ssl-images-amazon.com/images/I/51cUVaBWZzL._SX380_BO1,204,203,200_.jpg",
"author": "David Thomas, Andrew Hunt",
"url": "https://www.amazon.com/Pragmatic-Programmer-journey-mastery-Anniversary/dp/0135957052"
},
{
"title": "The Unicorn Project",
"image": "https://images-na.ssl-images-amazon.com/images/I/51A4T36jisL._SX334_BO1,204,203,200_.jpg",
"author": "Gene Kim",
"url": "https://www.amazon.com/Unicorn-Project-Developers-Disruption-Thriving/dp/1942788762"
},
{
"title": "The Passionate Programmer",
"image": "https://images-na.ssl-images-amazon.com/images/I/51m3yzmDFCL._SX331_BO1,204,203,200_.jpg",
"author": "Chad Fowler",
"url": "https://www.amazon.com/Passionate-Programmer-Remarkable-Development-Pragmatic-ebook/dp/B00AYQNR5U"
},
{
"title": "Hatching Twitter",
"image": "https://m.media-amazon.com/images/I/51YUkI5ZQ-L.jpg",
"author": "Nick Bilton",
"url": "https://www.amazon.com/Hatching-Twitter-Story-Friendship-Betrayal-ebook/dp/B00CDUVSQ0"
},
{
"title": "How Google Works",
"image": "https://images-na.ssl-images-amazon.com/images/I/31Xc+yFta0L._SX327_BO1,204,203,200_.jpg",
"author": "Eric Schmidt, Jonathan Rosenberg",
"url": "https://www.amazon.com/How-Google-Works-Eric-Schmidt/dp/1455582328"
},
{
"title": "Elon Musk",
"image": "https://m.media-amazon.com/images/I/51tw6UjHpDL.jpg",
"author": "Ashlee Vance",
"url": "https://www.amazon.com/Elon-Musk-SpaceX-Fantastic-Future-ebook/dp/B00KVI76ZS"
},
{
"title": "Six Easy Pieces",
"image": "https://m.media-amazon.com/images/I/51E53HCUKVL.jpg",
"author": "Richard P. Feynman",
"url": "https://www.amazon.com/Six-Easy-Pieces-Essentials-Explained-ebook/dp/B004OVEYNU"
},
{
"title": "Sapiens",
"image": "https://m.media-amazon.com/images/I/51Sn8PEXwcL.jpg",
"author": "Yuval Noah Harari",
"url": "https://www.amazon.com/Sapiens-Humankind-Yuval-Noah-Harari-ebook/dp/B00ICN066A"
}
]

Now that you have your books data, you need a component that can take this data and render it as a simple card in your React app:

Image for post
Image for post
A single card component

Building the Card component

The Card component will have four props to handle the data you passed into it:

<Card  
image="https://images-na.ssl-images-amazon.com/images/I/41dKkez-1rL._SX326_BO1,204,203,200_.jpg"
title="Steve Jobs"
author="Walter Isaacson"
url="https://www.amazon.com/Steve-Jobs-Walter-Isaacson/dp/1451648537"
/>

Here’s the JSX structure of the component:

const Card = ({image, title, author, url}) => {
return (
<div className="CardWrapper">
<div className="ColImg">
<img className="Img" src={image} alt={title} />
</div>
<div className="ColDetail">
<div className="Header">
<div className="BookTitle">{title}</div>
</div>
<div className="Description">{author}</div>
<a className="Link" href={url}>
Learn more
</a>
</div>
</div>
);
};

And here’s the styling for the component:

.CardWrapper {
flex: 0 1 300px;
margin: 12px;
overflow: hidden;
padding: 16px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05),
0 0px 10px rgba(0, 0, 0, 0.08);
border-radius: 5px;
flex-wrap: wrap;
min-width: 300px;
}.Header {
width: 100%;
display: flex;
margin-bottom: 10px;
}.ColImg {
width: 30%;
float: left;
}.ColDetail {
width: 70%;
float: left;
}.Img {
height: 100px;
}.BookTitle {
font-size: 20px;
}.Description {
color: #757575;
font-size: 14px;
margin-bottom:10px;
}.Link {
font-size: 14px;
}

You can also just download the component from my Bit collections:

npm install @bit/nsebhastian.react_fusejs.card

Then you can simply import the component to your App.js file. You just need to map() the JSON array into the Card component. Let’s add a <div> with the class name Container to improve the interface:

import React from "react";
import "./App.css";
import books from "./books.json";
import Card from "@bit/nsebhastian.react_fusejs.card";
function App() {
return (
<div className="Container">
{books.map((item) => (
<Card {...item} key={item.name} />
))}
</div>

);
}export default App;

Here’s the CSS for the Container class:

.Container {
width: 80%;
margin: 0 auto;
margin-top: 45px;
display: flex;
flex-wrap: wrap;
}

Now your list of cards is finished, let’s continue with building the Search component next.

Building the Search Component

The Search component is just a single text input with two props:

  • placeholder for the input placeholder text
  • onChange function to run when the user types into the input

Let’s write the JSX element for this component:

const SearchBar = ({onChange, placeholder}) => {
return (
<div className="Search">
<span className="SearchSpan">
<FaSearch />
</span>
<input
className="SearchInput"
type="text"
onChange={onChange}
placeholder={placeholder}
/>
</div>
);
};

Then, write the CSS for it:

.Search {
width: 400px;
margin: 0 auto;
position: relative;
display: flex;
}.SearchSpan {
width: 15%;
border: 1px solid #1C76D2;
background: #1C76D2;
padding-top: 4px;
text-align: center;
color: #fff;
border-radius: 5px 0 0 5px;
font-size: 20px;
}.SearchInput {
width: 85%;
border: 3px solid #1C76D2;
border-left: none;
padding: 5px;
border-radius: 0 5px 5px 0;
outline: none;
}

You can also use my shared component in Bit. Just install it with NPM:

npm install @bit/nsebhastian.react_fusejs.search-bar

Then import the component into your App.js file. Put both <SearchBar> component and the rest of the code in a single <div> element:

import React from "react";
import "./App.css";
import books from "./books.json";
import Card from "@bit/nsebhastian.react_fusejs.card";
import SearchBar from "@bit/nsebhastian.react_fusejs.search-bar";function App() {
return (
<div>
<h1 className="Title">My Favorite books</h1>
<SearchBar
placeholder="Search"
onChange={(e) => console.log(e.target.value)}
/>
<div className="Container">
{books.map((item) => (
<Card {...item} key={item.name} />
))}
</div>
</div>
);
}

Add a single CSS to App.css to center-align the <h1> element with the class Title:

.Title {
text-align: center;
}

Now you have all the components for this demo app. You only need to integrate Fuse.js into your React app for the final step.

Integrating Fuse.js to React app

To start integrating Fuse.js into your React app, you just need to install the NPM package into your project:

npm install fuse.js

Next, you need to import the library and create a new Fuse.js instance. The instance expects two parameters to be given:

  • The data to perform the search, could be a string array or object array
  • Additional options to change the behavior of the search

This means you need to pass the books array as the first argument. For the second argument, you need to pass in the keys array of title and author to prevent the search function from looking up the image and url strings.

import Fuse from "fuse.js";const fuse = new Fuse(books, {
keys: ["title", "author"],
});

Next, you need to call the function fuse.search() with any pattern that you want. The search will return a list of matches back as an array:

const matches = fuse.search("Elon Musk")// returns [{ item: object }]

Let’s think about the search behavior that’s suitable for the application. This should suffice:

  • When the user types into the search bar, the app will perform a search to the array
  • When there is any match, the app will return only books that match the pattern
  • When there is no match, the app will return an empty screen
  • When the user clears the search bar, the app will show all data without any filter.

To achieve that behavior, you need to put the books array into React state:

const [data, setData] = useState(books);

When the user types into the search bar, you need to run a function that will perform the search. Let’s call it the searchData function and pass the input value into it:

<SearchBar
placeholder="Search"
onChange={(e) => searchData(e.target.value)}
/>

Time to create the function. First, check on the pattern passed into the function. If the pattern is empty, just set the state back to books array and stop the function with return statement:

const searchData = (pattern) => {
if (!pattern) {
setData(books);
return;
}

Next, perform a search using the given pattern:

const fuse = new Fuse(data, {
keys: ["title", "author"],
});const result = fuse.search(pattern);

Create a new array called matches to store any match returned by Fuse. When the result is empty, set the data as an empty array:

const matches = [];
if (!result.length) {
setData([]);
}
else {
result.forEach(({item}) => {
matches.push(item);
});
setData(matches);
}

When the result is not empty, call the forEach function to iterate over the result and push each item into the array. Then update your state using the matches array:

if (!result.length) {
setData([]);
} else {
result.forEach(({item}) => {
matches.push(item);
});
setData(matches);
}

And with that, your application is complete. If you’re missing any step, you can compare your code with the demo:

Now you can search through your favorite book list. Awesome!

Conclusion

It’s important to help your users to actually find what they’re looking for, no matter what type of application you create. Fuse.js is an easy to use search library that doesn’t require any backend setup, and its fuzzy search technique will provide you with an error-tolerant search function.

Thank you for reading. I hope you learned something new from this tutorial.

Learn More


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK