I'm stucked, lost... I'm using gatsby-plugin-algolia, when I search, the empty fields are filtered. They are generated by the PostPreview component.
my archive.js in templates folder (to list blog posts):
imports....
// algolia search
import algoliasearch from 'algoliasearch/lite'
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom'
import PostPreview from '../components/postPreview/PostPreview'
const searchClient = algoliasearch(
'MY KEY...',
'MY KEY...'
)
const archiveTemplate = ({
data: { allWpPost },
pageContext: { catId, catName, catURI, categories, numPages, currentPage }
}) => {
return (
<Layout>
<Wrapper>
<BreadCrumbs
parent={{
uri: '/blog/todos-os-posts',
title: 'Blog'
}}
/>
<ContentWrapper>
<ArchiveSidebar catId={catId} categories={categories.edges} />
<PageContent>
<InstantSearch searchClient={searchClient} indexName="Gatsby">
<SearchBox />
<Hits hitComponent={PostPreview} />
</InstantSearch>
<h1 dangerouslySetInnerHTML={{ __html: catName }} />
{allWpPost.edges.map(post => (
<article key={post.node.id} className="entry-content">
<StyledDate
dangerouslySetInnerHTML={{ __html: post.node.date }}
/>
<Link to={`/blog${post.node.uri}`}>
<StyledH2
dangerouslySetInnerHTML={{ __html: post.node.title }}
/>
</Link>
<p dangerouslySetInnerHTML={{ __html: post.node.excerpt }}></p>
<StyledReadMore to={`/blog${post.node.uri}`}>
Leia +
</StyledReadMore>
<div className="dot-divider" />
</article>
))}
<Pagination
catUri={catURI} // from the context
page={currentPage}
totalPages={numPages}
/>
</PageContent>
</ContentWrapper>
</Wrapper>
</Layout>
)
}
export default archiveTemplate
export const pageQuery = graphql`
query($catId: String!, $skip: Int!, $limit: Int!) {
allWpPost(
filter: { categories: { nodes: { elemMatch: { id: { eq: $catId } } } } }
skip: $skip
limit: $limit
) {
edges {
node {
id
title
excerpt
uri
slug
date(formatString: "DD, MMMM, YYYY", locale: "pt")
}
}
}
}
`
My Algolia in Gatsby-config.js:
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
})
const AlgoliaBloghQuery = `
{
allWpPost {
nodes {
title
excerpt
id
}
}
}
`
Works:
My PostPreview component, here I'm lost.
imports...
const Postpreview = ({ id, title, date, excerpt, uri }) => {
return (
<div>
<article key={id} className="entry-content">
<StyledDate dangerouslySetInnerHTML={{ __html: date }} />
<Link to={`/blog${uri}`}>
<StyledH2 dangerouslySetInnerHTML={{ __html: title }} />
</Link>
<p dangerouslySetInnerHTML={{ __html: excerpt }}></p>
<StyledReadMore to={`/blog${uri}`}>Leia +</StyledReadMore>
<div className="dot-divider" />
</article>
</div>
)
}
export default Postpreview
I don't know how to get the data to pass to the props, I don't know if the queries are conflicting (archive.js - gatsby-config). Only read more button are rendered.
It's a broad question where multiple things can go wrong, I will try to answer the most common use case but it will need some effort on your side to debug and find the bug(s).
When dealing with Algolia + Gatsby, you are delegating to Algolia the responsibility of paginating, show/hide/render all certain posts, etc. So the following part, is redundant, should be removed:
{allWpPost.edges.map(post => (
<article key={post.node.id} className="entry-content">
<StyledDate
dangerouslySetInnerHTML={{ __html: post.node.date }}
/>
<Link to={`/blog${post.node.uri}`}>
<StyledH2
dangerouslySetInnerHTML={{ __html: post.node.title }}
/>
</Link>
<p dangerouslySetInnerHTML={{ __html: post.node.excerpt }}></p>
<StyledReadMore to={`/blog${post.node.uri}`}>
Leia +
</StyledReadMore>
<div className="dot-divider" />
</article>
))}
<Pagination
catUri={catURI} // from the context
page={currentPage}
totalPages={numPages}
/>
Algolia will show all posts by default if you are not searching anything (initial state).
Regarding the pagination, you have the Pagination
component from React InstantSearch, so you don't need to worry about it, Algolia handles it for you.
Everything that is related to Algolia's search must be wrapped inside InstantSearch
component, otherwise, it will never work.
Said that, your Searchbox
needs to refine the Algolia's result and should look like:
import React from "react"
import { connectSearchBox } from "react-instantsearch-dom"
import { Search as SearchIcon } from "@styled-icons/fa-solid"
export default connectSearchBox(
({ refine, currentRefinement, className, onFocus }) => (
<form className={className}>
<input
className="SearchInput"
type="text"
placeholder="Search"
aria-label="Search"
onChange={e => refine(e.target.value)}
value={currentRefinement}
onFocus={onFocus}
/>
<SearchIcon className="SearchIcon" />
</form>
)
)
Be aware of:
onChange={e => refine(e.target.value)}
value={currentRefinement}
Those are key lines and, if anything is not working as expected, try to print the values in a console.log
.
Here basically you are "connecting" the component to Algolia's API by connectSearchBox
HOC, which belongs to Algolia; it exposes the current search string as currentRefinement
and a function for changing it called refine
.
I don't know how to get the data to pass to the props, I don't know if the queries are conflicting (archive.js - gatsby-config). Only read more button are rendered.
The results, are called "hits" and what you are receiving as props
is a hit
, so, your PostPreview
should look like:
const Postpreview = ({ hit }) => {
console.log(hit);
let { id, title, date, excerpt, uri } = hit;
return (
<div>
<article key={id} className="entry-content">
<StyledDate dangerouslySetInnerHTML={{ __html: date }} />
<Link to={`/blog${uri}`}>
<StyledH2 dangerouslySetInnerHTML={{ __html: title }} />
</Link>
<p dangerouslySetInnerHTML={{ __html: excerpt }}></p>
<StyledReadMore to={`/blog${uri}`}>Leia +</StyledReadMore>
<div className="dot-divider" />
</article>
</div>
)
}
export default Postpreview
If the rest of the components are ok, you will get the hit
property which will contain all the needed data so you need to destructure it to get the data. Debug as needed, adding as many logs as needed.
You will find a detailed example (could be improved) in Gatsby's docs where the key components are:
import { Link } from "gatsby"
import { default as React } from "react"
import {
connectStateResults,
Highlight,
Hits,
Index,
Snippet,
PoweredBy,
} from "react-instantsearch-dom"
const HitCount = connectStateResults(({ searchResults }) => {
const hitCount = searchResults && searchResults.nbHits
return hitCount > 0 ? (
<div className="HitCount">
{hitCount} result{hitCount !== 1 ? `s` : ``}
</div>
) : null
})
const PageHit = ({ hit }) => (
<div>
<Link to={hit.slug}>
<h4>
<Highlight attribute="title" hit={hit} tagName="mark" />
</h4>
</Link>
<Snippet attribute="excerpt" hit={hit} tagName="mark" />
</div>
)
const HitsInIndex = ({ index }) => (
<Index indexName={index.name}>
<HitCount />
<Hits className="Hits" hitComponent={PageHit} />
</Index>
)
const SearchResult = ({ indices, className }) => (
<div className={className}>
{indices.map(index => (
<HitsInIndex index={index} key={index.name} />
))}
<PoweredBy />
</div>
)
export default SearchResult
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 from the InstantSearch library.
The PageHit
component is responsible for displaying a single page (“hit”) in a search result.
connectStateResults
wraps components to provide them with details about the current search such as the query, the number of results and timing statistics.
Highlight
and Snippet
both display attributes of matching search results to the user. The former renders the full value whereas the latter only shows a snippet. A snippet is the text immediately surrounding the match. The attribute
property is the name of the key in the Algolia index (as generated by pageToAlgoliaRecord
in algolia-queries.js
).
Overall, it seems that your page is rendering the correct amount the Postpreview
component but is not rendering the correct content because of the destructure of hit
.