skip to Main Content

I’ve got a small problem:

Context:

I have a a react page that contains, one component with two sub-components, the first sub-component contains the filters, and the second sub-component contains links for the same page(just a different title), so when I click on one link I get redirected to the same main component, just with different route, as shown below:

This is my design:

enter image description here

Since all the links point to the same main component, on the server side(using Next.js), I used generateStaticParams to dynamically generate all those pages.

Problem:

When I click on one of the links(Link component), I want to keep the same filter values(Filters component). So I want to keep the same state as the previous page by going to the new page with a different route.
The problem is that every time I click on one of the links, the new page is generated from the server side and I lose all the client data.

I’m looking for a good approach to solve this by not using localStorage. And I don’t want to pass the data as query parameters using <Link> from Next.
I thought also of using the Context, but it’s available just on the client side and the data will be lost after changing the route.

Is there a way to solve this, even by changing the current design?

I’m using React 19 and Next.js 15, any help will be very appreciated.

2

Answers


  1. generateStaticParams is executed at build time to pre-generate static pages for dynamic routes. It does not have access to runtime data like cookies or request-based data. Instead you can make your new page (where you want to access updated/current filter values) server side and access cookies() API from the next/headers. This API is available in the App Router Next.js 15 and allows you to read cookies directly on the server-side, ensuring that the data is available when the page is rendered. what you have to do is:

    1- Set cookies on the client-side when the user selects or updates a filter.

    2- Access cookies in your Server Component, you can access the cookies using next/headers.

      //FiltersComponent.tsx
        import Cookies from 'js-cookie';
        
        const FiltersComponent = () => {
          const handleFilterChange = (newCategory: string) => {
            // Set cookies on the client-side using js-cookie
            Cookies.set('category', newCategory, { expires: 7, path: '/' }); 
          };
        
          return (
            <div>
              <button onClick={() => handleFilterChange('electronics')}>Electronics</button>
           </div>
          );
        };
        
        export default FiltersComponent;
    

    Server-Side Page:

     //page.tsx (Server Component)
        import { cookies } from 'next/headers';
        
        const NewPage = () => {
          // Access cookies on the server-side using next/headers
          const cookieStore = cookies();
          const category = cookieStore.get('category'); 
        
          return (
            <div>
              <h1>Category: {category}</h1>
            </div>
          );
        };
        
        export default NewPage;
    
    Login or Signup to reply.
  2. If the state needs to persist across multiple pages and rehydration isn’t required (state doesn’t need to be saved server-side), you can use a React Context or a state management library like Zustand.

    Context Example:

    1. Create a FiltersContext to manage filters globally.
    2. Use the context in both your Filters and Links components.

    Try the below code once:

    import { createContext, useContext, useState } from 'react';
    import { useRouter } from 'next/router';
    
    const FiltersContext = createContext();
    
    export const FiltersProvider = ({ children }) => {
      const [filters, setFilters] = useState({ search: '', category: '' });
      return (
        <FiltersContext.Provider value={{ filters, setFilters }}>
          {children}
        </FiltersContext.Provider>
      );
    };
    
    const useFilters = () => useContext(FiltersContext);
    
    // Main Component
    const MainComponent = () => {
      const router = useRouter();
      const { filters, setFilters } = useFilters();
    
      const handleLinkClick = (route) => {
        router.push(route);
      };
    
      return (
        <div>
          <div>
            <input
              type="text"
              value={filters.search}
              onChange={(e) => setFilters({ ...filters, search: e.target.value })}
              placeholder="Search..."
            />
            <select
              value={filters.category}
              onChange={(e) => setFilters({ ...filters, category: e.target.value })}
            >
              <option value="">All</option>
              <option value="books">Books</option>
              <option value="electronics">Electronics</option>
            </select>
          </div>
          <div>
            <a onClick={() => handleLinkClick('/page1')}>Page 1</a>
            <a onClick={() => handleLinkClick('/page2')}>Page 2</a>
          </div>
        </div>
      );
    };
    
    // In _app.js
    import { FiltersProvider } from '../context/FiltersContext';
    
    export default function App({ Component, pageProps }) {
      return (
        <FiltersProvider>
          <Component {...pageProps} />
        </FiltersProvider>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search