search-ui icon indicating copy to clipboard operation
search-ui copied to clipboard

fail to work with Next.js Client-side navigations ( next/router, next/link )

Open jason-den opened this issue 4 years ago • 13 comments

Hi. I'm using search-ui with my Next.js project. But I found that when I navigate away from the search page to another page using the Client-side navigations, I cannot go back by using the browser "back" button (I've only tried chrome.)

It seems to be the only lib that support elastic-app-search. Is it correct?

How to replicate:

  1. Run this demo repo
  2. visit search page localhost:3001/search
  3. click go home page at the top of sidebar
  4. when home page complete rendering, click your browser back button like this: image

Problematic result: The URL do change to localhost:3001/search?...... but page remains in home page. image

I'm not sure this issue come from search-ui, not from Next.js. I guess this issue has something relate to Smart URL -- which I want to understand more but couldn't find much documents.

BTW I also tried search-ui with react router, they worked well with each other.

Any hint?

jason-den avatar Jan 14 '21 23:01 jason-den

Hi @jason-den. I ran your demo, I was able to reproduce.

Unfortunately, I don't have any hunches as to what's wrong.

Interesting to note though... when I set a breakpoint in search.jsx, it is never run. It's like the next router never successfully detects the route change.

When I remove Search UI, the issue is gone.

Something to do with query string in the URL and next? When search-ui initializes we rewrite /search to /search?size=n_20_n`. I don't know, just thinking out loud.

JasonStoltz avatar Feb 04 '21 14:02 JasonStoltz

I have an identical issue on my own Next.js project. What I noticed was that when I ran 'console.log(history)', unlike on other pages, the history.state was undefined. Could this be related?

CallumSlavin avatar Mar 30 '21 01:03 CallumSlavin

What I have also noticed is that this issue only seems to occur for me when using the Link component for page transitions.

CallumSlavin avatar Mar 30 '21 02:03 CallumSlavin

@CallumSlavin yep. if you replace all the related link with tag you will probably be fine. But it doesn't work with " Next.js Client-side navigations"

jason-den avatar Mar 30 '21 02:03 jason-den

For personal project it's an acceptable work around. but for project that has lots on link on that page using <Link /> on same page, it's not acceptable.

jason-den avatar Mar 30 '21 02:03 jason-den

Thanks again for raising this.

JasonStoltz avatar Mar 30 '21 12:03 JasonStoltz

We're running into this issue too. It seems that search-ui is replacing the NextJS state on initial search. One thing I've noticed is that the history states pushed by NextJS have this property: __N: true Perhaps Next is ignoring any state changes which don't have that property, or others (asPath, url)?

Maybe some kind of function could be added so that the state could be modified before search-ui pushes it?

ctestamarck avatar Apr 08 '21 15:04 ctestamarck

We also have this issue. Our workaround:

  1. Change trackUrlState to false (it actually fixes the issue, but if you want track URL state go to 2 and 3).
  2. Use onSearch to push state to query (you can use https://github.com/elastic/search-ui/blob/cb774e2ab1e6831ff40523c62d76b57d4c71ed5f/packages/search-ui/src/URLManager.js or write your own)
   onSearch: (state, queryConfig, next) => {
      const searchString = stateToQueryString(state)

      router.replace(
        `${window.location.pathname}?${searchString}`,
        undefined,
        { shallow: true }
      )

      return next(state, queryConfig)
    }
  1. Take the query params and set it to initialState on the component mount

Hope this will help

Yurii-Adamenko avatar Apr 26 '21 13:04 Yurii-Adamenko

@Yurii-Adamenko Nice workaround.

jason-den avatar Apr 28 '21 10:04 jason-den

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Is this issue still important to you? If so, please leave a comment and let us know. As always, thank you for your contributions.

botelastic[bot] avatar Jun 27 '21 10:06 botelastic[bot]

Thank you for posting that workaround @Yurii-Adamenko . Unfortunately I haven't been able to get it working when using the searchQuery property. If I comment out the searchQuery part then everything works as expected (except for a bug where the Searchbox will lose focus when a searchAsYouType search is applied):

<SearchProvider
        config={{
          apiConnector: connector,
          /*searchQuery: {
            disjunctiveFacets: ['make', 'model', 'year', 'collection_name', 'block_run_date'],
            facets: {
              year: { type: 'value', size: 250 },
              block_run_date: { type: 'value', size: 250 },
              make: { type: 'value', size: 250 },
              model: { type: 'value', size: 250 },
              collection_name: { type: 'value', size: 100 },
              reserve: { type: 'value' },
              is_charity: { type: 'value' },
            },
            filters: globalFilters,
          },*/
          initialState: {
            resultsPerPage: qstate.size ? qstate.size : 20,
            filters: qstate.filters ? qstate.filters : ifilters,
            sortField: qstate['sort-field'] ? qstate['sort-field'] : 'lot_number',
            sortDirection: qstate['sort-direction'] ? qstate['sort-direction'] : 'asc',
            current: qstate.current ? qstate.current : 1,
            searchTerm: qstate.q ? qstate.q : '',
          },
          trackUrlState: false,
          onSearch: (state, queryConfig, next) => {
      
            const searchString = stateToQueryString(state);
            router.replace(`${window.location.pathname}?${searchString}`, null, { shallow: true });
          
            return next(state, queryConfig);
          },
          alwaysSearchOnInitialLoad: false,
        }}
      >

If I uncomment the searchQuery part, it causes an infinite loop where search keeps re-running. The only place I'm using the NextJS router is for the router.replace

So I'm fairly confident there's nothing else interfering with the search state. Has anyone been able to get it working with a searchQuery? Thanks in advance for any help.

Edit: Removed the useEffect because it's not necessary.

ctestamarck avatar Jul 14 '21 19:07 ctestamarck

I've actually just found a workaround for the above searchQuery bug. If I apply those facets and filter in the beforeSearchCall function, it works correctly.

beforeSearchCall: (existingSearchOptions, next) => {

        const newConfig = {
          ...searchConfig,
          ...existingSearchOptions,
          filters: {
            all: [{ all: [{ auction_id: eventId }] }, ...existingSearchOptions.filters.all],
          },
        };

        return next(newConfig);
      },

However, the SearchBox still loses focus whenever a search is applied.

ctestamarck avatar Jul 14 '21 23:07 ctestamarck

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Is this issue still important to you? If so, please leave a comment and let us know. As always, thank you for your contributions.

botelastic[bot] avatar Sep 12 '21 23:09 botelastic[bot]

We have a same issue.

I believe the cause is that Search UI tempers and normalizes the URL to manage the state, for some interactions with the Search UI, the URL will be rewritten by Search UI after the initial loading, which messed up with the Next.js history management.

Possibly related to enhancement in this issue. https://github.com/elastic/search-ui/issues/790

weynhamz avatar Sep 20 '22 04:09 weynhamz