Add a Simple Search Function to React App without a Server
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
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:
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:
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 titleauthor
string for the authorimage
string for the book imagesrc
attributeurl
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:
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 textonChange
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
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK