Ok, I’ve experimented a lot, and it looks like ais-instant-search and ais-instant-search-ssr must have other ais components as direct children. Which means if I want to create reusable components for example for showing results (ais-hits wrapper) or for pagination (ais-paginate wrapper), I have to create routing/state mapping for each of them, besides just wrapping them around ais-instant-search-ssr component. I need reusable components, because I use them on three places in the application, and maybe they will be more in the future.
This is not very obvious in the documentation, and I was confused. Basically what I was thinking is that when I pass createServerRootMixin, it creates an instant search instance, which is actually the Helper, which makes the queries. Is that correct? Then, we pass that instance to the other components via provide. So, because of that, the nesting should not matter. It appears it does. That’s why was the confusion. It’s a bit hard to understand what is going on without looking at the source code. At the end, I came out with this mixin:
import algoliasearch from 'algoliasearch/lite'
import { createServerRootMixin, AisInstantSearchSsr } from 'vue-instantsearch'
const searchClient = algoliasearch(
process.env.NUXT_ENV_ALGOLIA_SEARCH_APP_ID,
process.env.NUXT_ENV_ALGOLIA_SEARCH_API_KEY,
)
function nuxtRouter(vueRouter) {
return {
read() {
return vueRouter ? vueRouter.currentRoute.query : ''
},
write(routeState) {
if (!vueRouter) return
vueRouter.push({
query: routeState,
})
},
createURL(routeState) {
return vueRouter.resolve({
query: routeState,
}).href
},
onUpdate(cb) {
if (typeof window === 'undefined') return
this._onPopState = event => {
const routeState = event.state
if (!routeState) {
cb(this.read())
} else {
cb(routeState)
}
}
window.addEventListener('popstate', this._onPopState)
},
dispose() {
if (typeof window === 'undefined') return
window.removeEventListener('popstate', this._onPopState)
},
}
}
export default function(stateMapping) {
return {
components: {
AisInstantSearchSsr,
},
provide() {
return {
$_ais_ssrInstantSearchInstance: this.instantsearch,
}
},
data() {
const mixin = createServerRootMixin({
searchClient,
indexName: 'products',
routing: {
router: nuxtRouter(this.$router),
stateMapping,
},
})
return {
...mixin.data(),
}
},
serverPrefetch() {
return this.instantsearch.findResultsState(this).then(algoliaState => {
this.$ssrContext.nuxt.algoliaState = algoliaState
})
},
beforeMount() {
const results =
this.$nuxt.context.nuxtState.algoliaState ||
window.__NUXT__.algoliaState
this.instantsearch.hydrate(results)
},
}
}
It appears that in situations where the ais components are on different places on the page, and not together like in the examples, it’s not very obvious how to do the things right.
Actually I realize that the children of ais-instant-search must be direct because otherwise they won’t be rendered until their parents are rendered. That’s why is the warn: “In order to have ‘query’ you must have searchbox, or infinitebox widgets”. Is that right?