Building a Tabbed search using multi-index - this is way more complicated than it should be #6519
Unanswered
mmorris8
asked this question in
Show and tell
Replies: 1 comment 2 replies
-
Thanks for sharing. Initially my intuition is that something that would make it simpler if you could put non-rendering facets in a root without index name as well. You obviously couldn't use a rendering refinement list (let's say) as the filters wouldn't match, but which widgets would you want at the empty root that aren't currently allowed? |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I've seen a couple of others ask how to set up a tabbed search with Algolia, and chose to do so for the Covenant Health search system. I've finally gotten a stable setup ready to go into UAT, but it's been two months of headaches. I'm posting portions of the code I wrote here to aid others who might want to try to do the same on their own site. I can share the link to our production site once given permission - I fear just dropping a link in at random will annoy the spambot and get the post trashed.
A word of caution - I'm not posting whole code in the snippets below - just enough to illustrate what's going on and why. So don't expect this code to just work if copied and pasted.
Overview
The React application uses react-router-dom v6 for client-side navigation between the tabs and react-aria Tabs to control the tab flows and make sure they are WAG compliant. The server is WordPress and the PHP route rewrite rules and driver code to setup the page is outside the scope of this discussion. Here we are focusing just on the React app itself. The site root sets up the React Router Dom using the createBrowserRouter function. PHP binds server information to the data elements of the react root and the root composes a global AppContext. So our root is
The application itself is divided into two components - the App and AppBody. Composed together their structure is as follows.
I've pruned off the other arguments sent to InstantSearch for the moment - don't worry we'll come back to it. But first let's deal with the ramifications of the one argument we did give it - root.
Setting up tabs - the root index
Algolia's documentation says it's ok without an indexName parameter, but it's not. You get an empty string index on the uiState that is difficult to work with and further cannot have anything other than a query attached. That's a problem because we need the tab state to be known to Algolia insofar as if the tab changes Algolia will sense a uiState change and respond appropriately.
But you can't just plop in an index that doesn't exist on your Algolia account - the search will crash when the server responds 404 no such index. You can however intercept the call. And you can compose your own search client to hand to InstantSearch. Here's the whole file with additional comments
Special thanks to Haroenv for helping me figure out the root filtering and insertion. With this in place we have a phantom root that will be in the uiState as "root" and have a menu item of tab. But this brings up two shortcomings in Algolia, or at least React Instant Search. First, I feel this phantom index trick is useful enough to be core, perhaps activated with the property of "isRootIndex" set to true. Second, the tab state is an example of routing information that can affect the route and state that isn't tied to any specific route. Tying it to the phantom root and then using a virtual menu widget is works, but doesn't feel elegant.
Setting up the InstantSearch component and URL Rewriting
Algolia's doesn't like it when widgets are unmounted and mounted, but that's a fact of life with a tabbed navigation. The solution I came up with is to track the UiState myself in the page context. Algolia just flat out loses track of things during the outlet mounting.
Algolia provides a listener, but react-router-dom doesn't have an event dispatcher to register the listener to, so it's necessary to manually fire the listener on tab navigations.
So let's look at the start of the App component. Note that it is defined in the same file as AppBody.
This part ended up straight forward, but there was quite a bit of thrashing along the way as I tried to find the exact moment the Algolia listener needed to fire before giving up and using a page context is unclear.
State mapping is next
Again, this landed on a rather straight forward approach, but the road to that was not easy.
Navigation
It's in the AppBody that we build our navigation function, and this is where the complexity starts
Getting the correct state on mount.
The final piece of the puzzle is to remount the trueUiState as a use effect in each of tab panel components. The code is the same for all.
Note that the uiState from Page Context isn't set yet we have nothing to do and the Algolia State should be accurate.
Anyway, the above does work, but it took 2 months to arrive at it travelling down multiple false paths and blind alleys. There has to be something that can be done in React Instantsearch Algolia core to make this less of a headache. Reviewing this post and converting it to a tutorial would be a start.
Beta Was this translation helpful? Give feedback.
All reactions