Quick Overview
When setting up client search, we usually rely on string comparison methods like indexOf, contains, etc. These methods work fine, but in real-life situations, users may search using incorrect spellings, jumbled sentences, and so on. Fuzzy Search helps us solve these issues.
Fuzzy Search
Fuzzy Search, also known as Approximate String Matching, is a technique used to find strings that are similar but not exactly the same.
Now, let’s get started with building the application.
We’ll set up a basic page that includes text and a search box.
Basic React App for Search Demo
A simple React application to demonstrate the search functionality.
Regular Search
Typically, we use string comparison methods like indexOf, contains, etc. These work well, but they fail to provide results if there are spelling mistakes in the search query.
Item.js:
Displays individual items with their logo, name, and tags.
import React from "react"; const Item = (props) => { return ( <div className="item"> <div className="logo"> <img src={props.logo} alt={props.name} /> </div> <div className="name"> <p>{props.name}</p> <div className="tags">{props.tags.join(", ")}</div> </div> </div> ); }; export default Item;
Data.js:
Contains an array of objects representing different technologies with their names, logos, and tags.
[ { "name": "Booty Bounce", "logo": "https://cdn.worldvectorlogo.com/logos/bootstrap-4.svg", "tags": ["dancing-css", "boot-stomping", "html-hop", "sass-swing"] }, { "name": "React-o-Rama", "logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1280px-React-icon.svg.png", "tags": ["spinny-js", "state-masters", "fronty-mcfrontend"] }, { "name": "Angu-latte", "logo": "https://angular.io/assets/images/logos/angular/angular.png", "tags": ["typescript-tornado", "web-zest", "framework-feels"] }, { "name": "Vue-tiful Bliss", "logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/1200px-Vue.js_Logo_2.svg.png", "tags": ["zen-js", "pretty-view", "framework-bae"] }, { "name": "Ant Party", "logo": "https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg", "tags": ["system-sass", "fancy-ui", "antd-vibes"] }, { "name": "Git Giggle", "logo": "https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png", "tags": ["commit-fun", "repo-riff", "c-git-jig"] }, { "name": "Gruntastic", "logo": "https://gruntjs.com/img/og.png", "tags": ["js-run-wild", "task-mania"] }, { "name": "jQuirky", "logo": "https://w7.pngwing.com/pngs/265/442/png-transparent-jquery-octos-global-javascript-library-document-object-model-ajax-framework-text-trademark-logo-thumbnail.png", "tags": ["selecto-magic", "fun-dome", "libra-party"] }, { "name": "D3-Licious", "logo": "https://raw.githubusercontent.com/d3/d3-logo/master/d3.png", "tags": ["data-candy", "viz-buzz", "chart-bliss"] } ]
Setting.js:
The code implements a search feature in a React app where users can search tools and technologies by name or tags. It filters the data in real-time, making the search case-insensitive, and updates the displayed results as the user types in the search box.
import React, { useState } from "react"; import data from "./data.json"; import Item from "./item"; const SettingsPage = () => { const [searchData, setSearchData] = useState(data); const searchItem = (query) => { if (!query) { setSearchData(data); return; } query = query.toLowerCase(); const finalResult = []; data.forEach((item) => { if ( item.name.toLowerCase().indexOf(query) !== -1 || item.tags.includes(query) ) { finalResult.push(item); } }); setSearchData(finalResult); }; return ( <div> <p className="title">Tools & Technologies</p> <div className="search-container"> <input type="search" onChange={(e) => searchItem(e.target.value)} placeholder="Search Technologies" /> </div> <div className="item-container"> {searchData.map((item) => ( <Item {...item} key={item.name} /> ))} </div> </div> ); }; export default SettingsPage;
Output:
Searched bot:
Searched booty:
I tried searching for “booty” and “bot,” but it only showed results for “booty” because the string comparison method works that way. To make the search fuzzy, we need a different string comparison algorithm.
There are many algorithms available for this, and you don’t need to study them all to use one.
To turn our search into a fuzzy search engine, we will use Fuse.js.
Fuse.js is a quick and lightweight fuzzy search library that doesn’t require any dependencies.
Integrating Fuse.js with Search
By making a small change, we can easily turn our search into a fuzzy search.
setting.js
Implements the fuzzy search functionality using Fuse.js. It allows users to search through the technologies by their name and tags. The search results are refreshed instantly as the user types.
import React, { useState } from "react"; import data from "./data.json"; import Fuse from "fuse.js"; import Item from "./item"; const SettingsPage = () => { const [searchData, setSearchData] = useState(data); const searchItem = (query) => { if (!query) { setSearchData(data); return; } const fuse = new Fuse(data, { keys: ["name", "tags"] }); const result = fuse.search(query); const finalResult = []; if (result.length) { result.forEach((item) => { finalResult.push(item.item); }); setSearchData(finalResult); } else { setSearchData([]); } }; return ( <div> <p className="title">Tools & Technologies</p> <div className="search-container"> <input type="search" onChange={(e) => searchItem(e.target.value)} placeholder="Search Technologies" /> </div> <div className="item-container"> {searchData.map((item) => ( <Item {...item} key={item.name} /> ))} </div> </div> ); }; export default SettingsPage;
Output:
Searched bot:
Searched booty:
Conclusion:
In this blog, we explored how traditional string comparison methods fall short in handling misspellings and inaccuracies in search queries. Fuzzy Search, implemented using Fuse.js, provides an efficient solution by enabling approximate string matching, making the search experience more robust and user-friendly. By integrating Fuse.js into a simple React application, we created a real-time search functionality that is case-insensitive, flexible, and capable of delivering accurate results even for imperfect queries. This lightweight library is a game-changer for enhancing search features in modern applications.