如何在你的 React 應用程式中實作即時搜尋
了解如何藉由 Meilisearch 和 React 的強大功能,輕鬆建立具有即時且可靠結果的搜尋型網路應用程式。

這篇文章最初由客座作者 Riccardo Giorato 於 2020 年 5 月發表,當時 Meilisearch 的版本為 v0.09。文章已由 Carolina Ferreira 更新,以適用於 Meilisearch v1。您可以在 GitHub 上找到此文章的第一個版本。
簡介
在本教學中,您將學習如何藉由 Meilisearch 的強大功能,輕鬆建立具有即時且可靠結果的搜尋型網路應用程式。
我們將涵蓋將資料新增至 Meilisearch 的基本步驟、建立自訂前端搜尋,並在最後進行自訂。
在本教學中,我們將為一個運動品牌建立即時搜尋體驗。以下是您將建立的內容預覽
先決條件
在開始之前,請確定您的機器上已安裝 Node.js >= 18。
您可以依照本教學,並在逐步完成的同時編寫程式碼,使用此 GitHub 專案。
最後,本教學假設您已熟悉 React。如果不是這樣,您可以查看 React 文件以了解更多資訊。
開始使用
複製儲存庫
使用以下指令複製 GitHub 儲存庫
git clone https://github.com/meilisearch/tutorials.git cd src/react-decathlon
執行新的 Docker 映像
如果您複製了儲存庫來設定 Meilisearch 執行個體,只需在主資料夾內執行以下指令
npm install npm run setup_meili
如果您沒有複製儲存庫,且想要使用 Docker 啟動 Meilisearch,請執行此指令
docker run -it --rm -p 7700:7700 -e MEILI_ENV='development' -v $(pwd)/meili_data:/meili_data getmeili/meilisearch:v1.0
依預設,Meilisearch 的 API 未受保護。您在生產環境中將需要主金鑰。您可以在我們的文件中了解更多相關資訊。
您可以造訪以下網址來檢查 Meilisearch 是否正在執行:https://127.0.0.1:7700/
想要避免在本機安裝嗎?為了快速建立一流的搜尋體驗,我們提供方便的 Meilisearch Cloud,這是 Meilisearch 的託管和完全管理版本。有 14 天的免費試用,無需信用卡 😉
在 Meilisearch 中建立索引
索引是一個儲存文件的實體,就像一個附加了一些特定設定和唯一 主索引鍵的物件陣列。
每個已建立索引的文件都必須有一個主欄位,這是一個必須存在於所有文件中的特殊欄位。此欄位保存文件的唯一值:其 ID。
Meilisearch 可以從您的資料集中推斷出主索引鍵,前提是資料集包含 id
子字串。您也可以明確設定它。
以下是要新增至 Meilisearch 的範例文件。
{ "id": 100013768717, "name": "Fitness Foldable Shoe Bag", "url": "https://www.decathlon.com/products/gym-foldable-shoe-bag", "vendor": "Domyos", "category": "Sport bag", "tags": [ "Artistic Gymnastics", "Boy's", "CARDIO_FITNESS_ACCESSORIES", "CARDIO_FITNESS_BAGS", "CODE_R3: 11782" ], "images": "https://cdn.shopify.com/s/files/1/1330/6287/products/sac_20a_20chaussure_20kaki_20_7C_20001_20_7C_20PSHOT_20_490180e6-44e4-4340-8e3d-c29eb70c6ac8.jpg?v=1584683232", "creation_date": "2020-04-03T15:58:48-07:00", "price": "2.49" }
您可以使用 REST 用戶端 (例如 Postman) 輕鬆建立此索引,但在本教學中,我們將使用 Meilisearch Javascript SDK 直接從 Node.js 執行此操作。
const { MeiliSearch } = require('meilisearch') ;(async () => { try { const config = { host: 'https://127.0.0.1:7700' }; const meili = new MeiliSearch(config); await meili.createIndex('decathlon'); // or you can set the primary key explicitly: // await meili.createIndex({ uid: "decathlon", primaryKey: "id" }); } catch (e) { console.error(e); console.log("Meili error: ", e.message); } })();
您可以在 Meilisearch 文件中閱讀更多關於索引屬性的資訊。
為文件建立索引
Meilisearch 接收 JSON 格式的文件並將它們儲存以供搜尋之用。這些文件由可以保存任何資料類型的欄位組成。Meilisearch 也接受以下格式的資料集:NDJSON 和 CSV。您可以在文件中閱讀更多關於格式的資訊。
在本教學中,您可以下載這個充滿運動服飾項目的資料集:decathlon.json
使用以下指令碼將此 JSON 檔案中的所有物件上傳至 Meilisearch。請記得在執行之前將路徑變更為您的 JSON 檔案!
const { MeiliSearch } = require('meilisearch') ;(async () => { try { const config = { host: 'https://127.0.0.1:7700' }; const meili = new MeiliSearch(config); const decathlon = require("../decathlon.json"); // path to json file const index = meili.index("decathlon"); await index.addDocuments(decathlon); } catch (e) { console.error(e); console.log("Meili error: ", e.message); } })();
準備 React 應用程式
我們需要一個標準的 React 應用程式。您可以使用您先前在開始使用章節中複製的專案。
如果您偏好從空白應用程式開始,您可以使用以下指令,使用 Create React App 建立您自己的應用程式。您可以隨意命名應用程式。
npx create-react-app meili_react_demo cd meili_react_demo
包含 Tailwind CSS
為了加快樣式處理程序,請將 Tailwind CSS 樣式直接新增至 index.html 檔案的 <head>
元素中
<script src="https://cdn.tailwindcss.com"></script>
設定 App.js 狀態
然後,使用此程式碼修改 App.js
檔案,以設定簡單的搜尋表單和一些狀態變數來處理搜尋的每個方面。
import React, { useState, useEffect } from 'react' import { MeiliSearch } from 'meilisearch' import Item from './components/Item' // TODO configure the MeiliSearch Client const index = client.index('decathlon') function App () { const [searchedWord, setSearch] = useState('') const [resultSearch, setResults] = useState([]) // TODO add function to send searchedWord to Meilisearch return ( <div className='mx-auto'> <div className='header font-sans text-white items-center justify-center'> <header className='py-12'> <img className='h-20 w-auto items-center justify-center p-2 mx-auto' src='/wide_logo.png' style={{ filter: 'invert(0%)' }} alt='Decathlon logo' /> <h1 className='flex flex-wrap flex-grow text-3xl w-full justify-center p-4'> Stop looking for an item — find it and work hard! </h1> <div className='border rounded overflow-hidden w-full flex justify-center mx-auto searchBox mt-6'> <button className='flex items-center justify-center px-4 shadow-md bg-white text-black'> <svg className='h-4 w-4 text-grey-dark' fill='currentColor' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' > <path d='M16.32 14.9l5.39 5.4a1 1 0 0 1-1.42 1.4l-5.38-5.38a8 8 0 1 1 1.41-1.41zM10 16a6 6 0 1 0 0-12 6 6 0 0 0 0 12z' /> </svg> </button> <input type='text' value={searchedWord} onChange={(event) => setSearch(event.target.value)} className='px-6 py-4 w-full text-black' placeholder='Product, sport, color, …' /> </div> </header> </div> <div> <div className='flex flex-wrap searchResults'> // TODO iterate over the search results to display them with the Item component </div> </div> </div> ) } export default App
此程式碼應輸出這個具有搜尋表單的美麗標頭。
React 中的搜尋結果
使用 Javascript SDK 將 React 與 Meilisearch 連接起來,只需幾個步驟即可完成。
Meilisearch 用戶端
使用以下指令安裝 Meilisearch SDK
// if you use npm npm install meilisearch // if you use yarn yarn add meilisearch
使用伺服器 URL 設定 Meilisearch 用戶端。在我們的案例中,它是本機 Docker 機器。最後,從後端載入正確的索引。
將 App.js
中的此註解取代為以下程式碼片段
"// TODO 設定 Meilisearch 用戶端"
import { MeiliSearch } from "meilisearch"; const client = new MeiliSearch({ host: "https://127.0.0.1:7700/", }); const index = client.index("decathlon");
傳送搜尋查詢
新增一個 useEffect
hook,以執行在 Meilisearch 中輸入的單字搜尋。所有結果都將設定為一個稱為 resultsSearch
的簡單狀態變數。
將 App.js
中的此註解取代為以下程式碼片段
"// TODO 新增函數以將 searchedWord 傳送至 Meilisearch"
useEffect(() => { // Create a scoped async function in the hook async function searchWithMeili() { const search = await index.search(searchedWord); setResults(search.hits); } // Execute the created function directly searchWithMeili(); }, [searchedWord]);
展示結果
您將逐一查看 Meilisearch 傳回的 JSON 物件 — 它們的結構將與上傳的 JSON 物件相同 — 並且您將在 Item
元件中顯示它們,並連結至產品頁面。
讓我們建立 Item
元件,以協助我們顯示產品。建立一個 components 資料夾,其中包含一個 Item.js
檔案,並複製貼上以下程式碼片段
function Item ({ url, image, name, category, vendor, price, id }) { return ( <div className='flex w-full sm:w-1/2 md:w-1/3 lg:w-1/4 xl:w-1/6 p-3' key={id}> <a className='flex-1 rounded overflow-hidden shadow-lg' href={url}> <img className='w-full h-48 object-cover' src={image} alt={name} onError={(e) => { e.target.onerror = null e.target.src = '/wide_logo.png' }} /> <div className='px-6 py-3'> <div className='font-bold text-sm mb-1 text-gray-600 capitalize'> {category} </div> {name} <div className='font-bold text-xl mb-2 text-gray-800'> {vendor} - </div> <p className='text-black text-xl font-bold text-base py-2'> $ {price} </p> </div> </a> </div> ) } export default Item
然後,將 App.js
中的此註解取代為以下程式碼片段
{resultSearch?.map((result) => ( <Item url={result.url} image={result.images} name={result.name} category={result.category} vendor={result.vendor} price={result.price} key={result.id} /> ))}
您可以在 GitHub 上查看完整程式碼。
設定搜尋
使用 Meilisearch,您可以獲得大量的自訂選項,以微調您的搜尋體驗。我們將在這裡查看一些功能。您可以在文件中閱讀更多相關資訊。
搜尋排名
我們將從變更排名規則開始,Meilisearch 會使用這些規則來排序您在進行搜尋查詢時上傳的文件。排名規則的順序會影響搜尋結果的相關性。您可以在文件中了解更多相關資訊。
讓我們使用以下順序
[ "words", "typo", "proximity", "attribute", "sort", "exactness", “creation_date:desc” ]
這會使用預設順序以及自訂規則:creation_date
。如果所有先前的值都相同,此規則會按項目的建立日期對其進行排名。
可搜尋的屬性
您也可以設定可搜尋的屬性。這些是 Meilisearch 搜尋其值以符合查詢字詞的屬性。依預設,所有屬性都是可搜尋的,但您可以設定為僅搜尋 name
、vendor
、category
和 tags
欄位,而排除 images
和 URL
searchableAttributes: ["name", "vendor", "category", "tags"]
顯示的屬性
顯示屬性是指 Meilisearch 可以透過 displayedAttributes 陣列,在前端應用程式中回傳給使用者的屬性。與可搜尋屬性類似,預設會顯示所有屬性。
"displayedAttributes": [ "name", "vendor", "category", "tags", "images", "url" ]
將新設定上傳到 Meilisearch
現在是時候使用上述說明過的搜尋設定,來客製化我們的 Meilisearch 索引了。
const { MeiliSearch } = require('meilisearch') ;(async () => { try { const config = { host: 'https://127.0.0.1:7700' }; const meili = new MeiliSearch(config); const index = meili.index("decathlon"); const newSettings = { rankingRules: [ "words", "typo", "proximity", "attribute", "sort", "exactness", "creation_date:desc" ], searchableAttributes: ["name", "vendor", "category", "tags"], displayedAttributes: [ "name", "vendor", "category", "tags", "images", "url" ] }; await index.updateSettings(newSettings); } catch (e) { console.error(e); console.log("Meili error: ", e.message); } })();
結論
如果沒有一個令人難以置信的團隊日夜投入這個偉大的專案,這個快速搜尋就不可能實現!如果您喜歡為 Meilisearch 這個大家庭做出貢獻,請查看以下儲存庫
訂閱我們的電子報,直接將這些每月更新資訊傳送到您的收件匣。
如需更多關於 Meilisearch 的資訊,請加入我們在 Discord 上的開發者社群。您可以查看路線圖,並參與產品討論,以了解更多關於該產品的資訊。