Skip to content

Commit 5bd48a5

Browse files
authored
chore(docs): update algolia guide (#38085)
1 parent 89a3232 commit 5bd48a5

File tree

2 files changed

+48
-45
lines changed

2 files changed

+48
-45
lines changed

docs/docs/adding-search-with-algolia.md

+48-45
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ There are two stages to providing search functionality: indexing your pages and
1818

1919
The [Gatsby Algolia plugin](https://github.com/algolia/gatsby-plugin-algolia) handles the indexing. It sends your pages to Algolia for indexing every time you run `gatsby build`. You use GraphQL to customize which pages and what information to index.
2020

21-
To build the user interface for searching, this guide will use [React InstantSearch](https://www.algolia.com/doc/guides/building-search-ui/getting-started/react/), which is a library provided by Algolia with ready-made React components. This is the quickest way to get up and running, but you could also build your own custom user interface.
21+
To build the user interface for searching, this guide will use [React InstantSearch Hooks](https://www.algolia.com/doc/guides/building-search-ui/getting-started/react-hooks/), which is a library provided by Algolia with ready-made React components. This is the quickest way to get up and running, but you could also build your own custom user interface.
2222

2323
> Note: If you want to build a search for technical documentation, Algolia provides a product called [DocSearch](https://docsearch.algolia.com/) that simplifies the process further and eliminates the need for manual indexing. This is the preferred approach for documentation sites.
2424
@@ -189,7 +189,7 @@ Now that there is data in the index, it is time to build the user interface for
189189

190190
The guide will use the following frameworks:
191191

192-
- [React InstantSearch](https://community.algolia.com/react-instantsearch), a component library provided by Algolia for easily building search interfaces.
192+
- [React InstantSearch Hooks](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/), a component library provided by Algolia for easily building search interfaces.
193193
- [Algolia Search](https://www.npmjs.com/package/algoliasearch) provides the API client for calling Algolia.
194194
- [Styled Components](https://styled-components.com) for embedding the CSS in the code, integrated using the [Gatsby styled component plugin](/plugins/gatsby-plugin-styled-components/).
195195
- [Styled Icons](https://styled-icons.js.org/) provides the magnifying glass icon for the search bar.
@@ -199,7 +199,7 @@ Styled Components can also be replaced by any other CSS solution you prefer.
199199
Install these frameworks by running the following command:
200200

201201
```shell
202-
npm install react-instantsearch-dom algoliasearch styled-components gatsby-plugin-styled-components @styled-icons/fa-solid
202+
npm install react-instantsearch-hooks-web algoliasearch styled-components gatsby-plugin-styled-components @styled-icons/fa-solid
203203
```
204204

205205
Add the `gatsby-plugin-styled-components` to your `gatsby-config`:
@@ -218,63 +218,70 @@ The first step is to create the input field where the user enters the search que
218218

219219
```jsx:title=src/components/search/search-box.js
220220
import React from "react"
221-
import { connectSearchBox } from "react-instantsearch-dom"
221+
import { useSearchBox } from "react-instantsearch-hooks-web"
222222
import { Search as SearchIcon } from "@styled-icons/fa-solid"
223223

224-
export default connectSearchBox(
225-
({ refine, currentRefinement, className, onFocus }) => (
224+
const SearchBox = ({ className, onFocus, onChange }) => {
225+
const { query, refine } = useSearchBox()
226+
227+
return (
226228
<form className={className}>
227229
<input
228230
className="SearchInput"
229231
type="text"
230232
placeholder="Search"
231233
aria-label="Search"
232-
onChange={e => refine(e.target.value)}
233-
value={currentRefinement}
234+
onChange={e => {
235+
refine(e.target.value)
236+
onChange(e.target.value)
237+
}}
238+
value={query}
234239
onFocus={onFocus}
235240
/>
236241
<SearchIcon className="SearchIcon" />
237242
</form>
238243
)
239-
)
244+
}
245+
246+
export default SearchBox
240247
```
241248

242-
The component consists of an HTML form containing an input field and the magnifying glass icon. Most of the work is done by Algolia's [`connectSearchBox`](https://community.algolia.com/react-instantsearch/connectors/connectSearchBox.html) function. It exposes the current search string as `currentRefinement` and a function for changing it called `refine`.
249+
The component consists of an HTML form containing an input field and the magnifying glass icon. Most of the work is done by Algolia's [`useSearchBox`](https://www.algolia.com/doc/api-reference/widgets/search-box/react-hooks/#hook) React hook. It exposes the current search string as `query` and a function for changing it called `refine`.
243250

244251
### Displaying search results
245252

246253
That's all there is to entering the search query. Next, build a component for displaying search results:
247254

248255
```jsx:title=src/components/search/search-result.js
256+
import React from "react"
249257
import { Link } from "gatsby"
250-
import { default as React } from "react"
251258
import {
252-
connectStateResults,
253259
Highlight,
254260
Hits,
255261
Index,
256262
Snippet,
257263
PoweredBy,
258-
} from "react-instantsearch-dom"
264+
useStats,
265+
} from "react-instantsearch-hooks-web"
259266

260-
const HitCount = connectStateResults(({ searchResults }) => {
261-
const hitCount = searchResults && searchResults.nbHits
267+
const HitCount = () => {
268+
const { nbHits } = useStats()
262269

263-
return hitCount > 0 ? (
270+
return nbHits > 0 ? (
264271
<div className="HitCount">
265-
{hitCount} result{hitCount !== 1 ? `s` : ``}
272+
{nbHits} result{nbHits !== 1 ? "s" : ""}
266273
</div>
267274
) : null
268-
})
275+
}
269276

270277
const PageHit = ({ hit }) => (
271278
<div>
272279
<Link to={hit.slug}>
273280
<h4>
274-
<Highlight attribute="title" hit={hit} tagName="mark" />
281+
<Highlight attribute="title" hit={hit} />
275282
</h4>
276283
</Link>
277-
<Snippet attribute="excerpt" hit={hit} tagName="mark" />
284+
<Snippet attribute="excerpt" hit={hit} />
278285
</div>
279286
)
280287

@@ -297,11 +304,11 @@ const SearchResult = ({ indices, className }) => (
297304
export default SearchResult
298305
```
299306

300-
Since Algolia supports multiple indices, the `SearchResult` iterates over all indices and displays hits for each of them using the `HitsInIndex` component. It, in turn, relies heavily on the [`Hits` component](https://www.algolia.com/doc/api-reference/widgets/hits/react/) from the InstantSearch library.
307+
Since Algolia supports multiple indices, the `SearchResult` iterates over all indices and displays hits for each of them using the `HitsInIndex` component. It, in turn, relies heavily on the [`Hits` component](https://www.algolia.com/doc/api-reference/widgets/hits/react-hooks/) from the InstantSearch library.
301308

302309
The `PageHit` component is responsible for displaying a single page ("hit") in a search result.
303310

304-
[`connectStateResults`](https://community.algolia.com/react-instantsearch/connectors/connectStateResults.html) wraps components to provide them with details about the current search such as the query, the number of results and timing statistics.
311+
[`useStats()`](https://www.algolia.com/doc/api-reference/widgets/stats/react-hooks/) provides details about the current search such as the query, the number of results and timing statistics.
305312

306313
If you're using Algolia's free tier, they ask you to acknowledge the use of their technology by including the string "Powered by Algolia", which is what `PoweredBy` does.
307314

@@ -312,9 +319,9 @@ If you're using Algolia's free tier, they ask you to acknowledge the use of thei
312319
You now need to hook up the two components to each other and perform the actual search:
313320

314321
```jsx:title=src/components/search/index.js
322+
import React, { createRef, useState, useMemo } from "react"
315323
import algoliasearch from "algoliasearch/lite"
316-
import { createRef, default as React, useState, useMemo } from "react"
317-
import { InstantSearch } from "react-instantsearch-dom"
324+
import { InstantSearch } from "react-instantsearch-hooks-web"
318325
import { ThemeProvider } from "styled-components"
319326
import StyledSearchBox from "./styled-search-box"
320327
import StyledSearchResult from "./styled-search-result"
@@ -345,12 +352,12 @@ export default function Search({ indices }) {
345352
return (
346353
<ThemeProvider theme={theme}>
347354
<StyledSearchRoot ref={rootRef}>
348-
<InstantSearch
349-
searchClient={searchClient}
350-
indexName={indices[0].name}
351-
onSearchStateChange={({ query }) => setQuery(query)}
352-
>
353-
<StyledSearchBox onFocus={() => setFocus(true)} hasFocus={hasFocus} />
355+
<InstantSearch searchClient={searchClient} indexName={indices[0].name}>
356+
<StyledSearchBox
357+
onChange={query => setQuery(query)}
358+
onFocus={() => setFocus(true)}
359+
hasFocus={hasFocus}
360+
/>
354361
<StyledSearchResult
355362
show={query && query.length > 0 && hasFocus}
356363
indices={indices}
@@ -370,7 +377,7 @@ The `searchClient` variable is [memoized](https://reactjs.org/docs/hooks-referen
370377

371378
`StyledSearchRoot` is the root of the whole component. The React hook `useClickOutside` provides a callback if the user clicks anywhere else on the page, in which case it should close.
372379

373-
`InstantSearch` from [`react-instantsearch-dom`](https://community.algolia.com/react-instantsearch) wraps the search box and search results to orchestrate the search.
380+
`InstantSearch` from [`react-instantsearch-hooks-web`](https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/) wraps the search box and search results to orchestrate the search.
374381

375382
### Supporting files
376383

@@ -381,7 +388,7 @@ import { useEffect } from "react"
381388

382389
const events = [`mousedown`, `touchstart`]
383390

384-
export default (ref, onClickOutside) => {
391+
const useClickOutside = (ref, onClickOutside) => {
385392
const isOutside = element => !ref.current || !ref.current.contains(element)
386393

387394
const onClick = event => {
@@ -400,6 +407,8 @@ export default (ref, onClickOutside) => {
400407
}
401408
})
402409
}
410+
411+
export default useClickOutside
403412
```
404413

405414
And finally, you should also add some CSS. The `Styled` components wrap the components you wrote earlier to add styling to them. If you wish to use a different CSS framework, you can skip these. In that case, replace `StyledSearchBox` with `SearchBox`, `StyledSearchResult` with `SearchResult` and `StyledSearchRoot` with `<div>` in `index.js`.
@@ -459,6 +468,7 @@ export default styled(SearchBox)`
459468
margin: 0.3em;
460469
color: ${({ theme }) => theme.foreground};
461470
pointer-events: none;
471+
z-index: 1;
462472
}
463473
`
464474
```
@@ -498,7 +508,7 @@ export default styled(SearchResult)`
498508
}
499509
500510
.Hits {
501-
ul {
511+
ol {
502512
list-style: none;
503513
margin-left: 0;
504514
}
@@ -510,6 +520,7 @@ export default styled(SearchResult)`
510520
color: ${({ theme }) => theme.foreground};
511521
512522
h4 {
523+
margin-top: 0;
513524
margin-bottom: 0.2em;
514525
}
515526
}
@@ -522,7 +533,7 @@ export default styled(SearchResult)`
522533
font-size: 80%;
523534
524535
svg {
525-
width: 70px;
536+
width: 130px;
526537
}
527538
}
528539
`
@@ -537,7 +548,6 @@ The search widget is now ready for use. It needs to be placed somewhere in your
537548
```jsx:title=src/components/layout.js
538549
import React from "react"
539550
import { Link } from "gatsby"
540-
import { rhythm, scale } from "../utils/typography"
541551
// highlight-start
542552
import Search from "./search"
543553

@@ -548,15 +558,8 @@ const Layout = ({ location, title, children }) => {
548558
// ...
549559

550560
return (
551-
<div
552-
style={{
553-
marginLeft: `auto`,
554-
marginRight: `auto`,
555-
maxWidth: rhythm(24),
556-
padding: `${rhythm(1.5)} ${rhythm(3 / 4)}`,
557-
}}
558-
>
559-
<header>
561+
<div className="global-wrapper" data-is-root-path={isRootPath}>
562+
<header className="global-header">
560563
// highlight-next-line
561564
<Search indices={searchIndices} />
562565
{header}
@@ -584,7 +587,7 @@ Running `gatsby develop` should now give you a working search that looks somethi
584587

585588
![Search widget displaying search results](./images/algolia-final-search.png)
586589

587-
You can also play around with it at [https://janosh.io/blog](https://janosh.io/blog).
590+
You can also play around with it at [https://gatsby-react-instantsearch-hooks.netlify.app](https://gatsby-react-instantsearch-hooks.netlify.app).
588591

589592
## Deploying to Netlify
590593

30.4 KB
Loading

0 commit comments

Comments
 (0)