ReferenceError: window is not defined
Answered
berkserbet posted this in #help-forum
I have an app that I cleaned up and mostly moved from client side to server side last night thanks to DirtyCajunRice!
Only issue is that on my builds I can't access query parameters, on development I can. I see this in my console logs:
I'm guessing that is the reason. Here is my page.tsx:
types.tsx:
First few lines of ProductCards.tsx
Can share anything else that helps!
Only issue is that on my builds I can't access query parameters, on development I can. I see this in my console logs:
ReferenceError: window is not defined
at n (/Users/berkserbetcioglu/Code/storefront/.next/server/app/[...r]/page.js:1:2996)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:47419)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64674)
at nI (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:46806)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:47570)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:61663)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64674)
at nB (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:67657)
at nF (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:66824)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64990)I'm guessing that is the reason. Here is my page.tsx:
import React from 'react'
import ProductCards from './ProductCards';
import { ProductSearchParams } from '@/types/products';
interface Props {
searchParams: ProductSearchParams
}
export default function Home({ searchParams }: Props) {
console.log("searchParams", searchParams);
return (
<main>
<ProductCards {...searchParams} />
</main>
);
}types.tsx:
export const allSearchParams = ['r', 'search', 'genders', 'sizes', 'conditions', 'countries', 'brands', 'pages'] as const;
export type ProductSearchParam = typeof allSearchParams[number];
export type ProductSearchParams = Record<ProductSearchParam, string | string[]>;
export interface Product {
title: string;
brands: string[];
actions: string[];
status: string | null;
genders: string[];
sizes: string[];
categories: string[];
price: number | null;
currency: string | null;
countries: string[];
images: string[];
conditions: string[];
colors: string[];
shipping_info: string | null;
search_keywords: string | null;
timestamp: number; // in seconds
source: string;
reddit_subreddit: string;
reddit_author: string;
reddit_post_id: string | null;
reddit_thread_id?: string | null;
reddit_comment_id: string | null;
listing_number: number;
}First few lines of ProductCards.tsx
import React, { Suspense } from 'react'
import Link from 'next/link'
import SearchContainer from './SearchContainer';
import { CustomImage, DefaultImage } from './image';
import products from '@/json/listings.json'
import { allSearchParams, ProductSearchParam, ProductSearchParams, Product } from '@/types/products';
import { redirect } from 'next/navigation'
import { CheckBox } from './checkbox';
function sanitize(params: ProductSearchParams) {
const stringsOnly = Object.fromEntries(Object.entries(params).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v]));
return {... stringsOnly, pages: Number(stringsOnly.pages)} as Record<Exclude<ProductSearchParam, 'pages'>, string> & { pages: number };
}
const ProductCards = (props: ProductSearchParams) => {
const initialParams = sanitize(props)
console.log("Initial Params:", initialParams)Can share anything else that helps!
Answered by Plott Hound
When you change your search params the data will become stale because the app hasn’t been told that the data is stale so there was no need to fetch it again. If you call revalidatePath it will trigger the fetch to run again with the new parameters
294 Replies
I'm seeing that something related to
useEffect() needs to be done here, but unfortunately I am a bit too new to quickly understandYup!
@berkserbet I'm seeing that something related to `useEffect()` needs to be done here, but unfortunately I am a bit too new to quickly understand
this error is caused by rendering on server and
window is a browser api which is not availble in nodeSearchContainer has window:
'use client'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
import { useState } from 'react'
const SearchContainer = () => {
// NextJs Navigation
const router = useRouter()
const searchParams = useSearchParams()
const pathname = usePathname()
let queryParams: URLSearchParams;
// React States
const [search, setSearch] = useState(searchParams.get('search') || '')
// Handle Submitting
const handleSubmit = (e: any) => {
e.preventDefault()
if (typeof window !== "undefined") {
queryParams = new URLSearchParams(window.location.search);
}
queryParams.delete("pages");
if (search === '') {
queryParams.delete('search');
} else {
queryParams.set('search', search);
}
const path = window.location.pathname + "?" + queryParams.toString();
router.push(path);
}
const removeSearch = (e: any) => {
router.push(pathname)
return
}
return (
<form>
<input className='border border-gray-400 rounded-md p-1' placeholder='Search' onChange={(e) => setSearch(e.target.value)} defaultValue={search}/>
<button className='border border-gray-400 rounded-md p-1 m-2 hover:bg-blue-100' type='submit' onClick={handleSubmit}>ðŸ”</button>
<button type='submit' onClick={removeSearch}>✖ï¸</button>
</form>
)
}
export default SearchContainerI call this in ProductCards.tsx
@berkserbet I call this in ProductCards.tsx
ok could you show the rest of the code in
ProductCardsYup
just call it in the return
<div className="flex justify-center items-center">
<Suspense>
<SearchContainer/>
</Suspense>
</div>Even when I take out SearchContainer I get the same error
@berkserbet Even when I take out SearchContainer I get the same error
you sure the error is cause by this page?
I don't see any issue yet
I am not
@berkserbet I am not
ok when you see the error?
In my terminal
ReferenceError: window is not defined
at n (/Users/berkserbetcioglu/Code/storefront/.next/server/app/[...r]/page.js:1:2996)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:47419)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64674)
at nI (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:46806)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:47570)
at nM (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:61663)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64674)
at nB (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:67657)
at nF (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:66824)
at nN (/Users/berkserbetcioglu/Code/storefront/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:12:64990)npm run build?
no error with npm run dev?
npm start*
do you have a route at
app/[...r]/page.tsxI do!
show the code on that page
'use client'
import React from 'react'
import { redirect } from 'next/navigation';
import { usePathname } from 'next/navigation'
export default function SubredditRedirect() {
const pathname = usePathname()
const queryParams = new URLSearchParams(window.location.search);
if (queryParams.toString()) {
redirect('/' + "?r=" + pathname.split('/')[2] + "&" + queryParams.toString())
} else {
redirect('/' + "?r=" + pathname.split('/')[2])
}
}const queryParams = new URLSearchParams(window.location.search);Is that the line with the bug
yes
change to
const queryParams = useSearchParams()and wrap this component with
Suspenseor is this a page?
Its a page
It redirects
I turn /r/name to ?r=name
It looks like that error is gone by my query params still aren't working in the app on build
@berkserbet 'use client'
import React from 'react'
import { redirect } from 'next/navigation';
import { usePathname } from 'next/navigation'
export default function SubredditRedirect() {
const pathname = usePathname()
const queryParams = new URLSearchParams(window.location.search);
if (queryParams.toString()) {
redirect('/' + "?r=" + pathname.split('/')[2] + "&" + queryParams.toString())
} else {
redirect('/' + "?r=" + pathname.split('/')[2])
}
}
ok do this
export default function SubredditRedirect({
params,
searchParams,
}: {
params: string[];
searchParams: { [key: string]: string };
}) {
if (searchParams.toString()) {
redirect(
"/" + "?r=" + params[1] + "&" + searchParams.toString()
);
} else {
redirect("/" + "?r=" + params[1]);
}
}remove
'use client'On it
@Ray ok do this
ts
export default function SubredditRedirect({
params,
searchParams,
}: {
params: string[];
searchParams: { [key: string]: string };
}) {
if (searchParams.toString()) {
redirect(
"/" + "?r=" + params[1] + "&" + searchParams.toString()
);
} else {
redirect("/" + "?r=" + params[1]);
}
}
It became
?r=undefined&[object%20Object]@berkserbet I turn /r/name to ?r=name
what is the name if they access /r ?
it can be anything
Any subreddit name
what is the file path?
I mean if they go to url
/rYes
@berkserbet Yes
import { notFound, redirect } from "next/navigation";
export default function SubredditRedirect({
params,
searchParams,
}: {
params: string[];
searchParams: { [key: string]: string };
}) {
if (params.length < 1) notFound()
if (searchParams) {
redirect(
"/" +
"?r=" +
params[1] +
"&" +
new URLSearchParams(searchParams).toString()
);
} else {
redirect("/" + "?r=" + params[1]);
}
}@berkserbet Now I get /?r=undefined&
import { notFound, redirect } from "next/navigation";
export default function SubredditRedirect({
params,
searchParams,
}: {
params: {r: string[]};
searchParams: { [key: string]: string };
}) {
if (params.r.length < 1) notFound()
if (searchParams) {
redirect(
"/" +
"?r=" +
params.r[1] +
"&" +
new URLSearchParams(searchParams).toString()
);
} else {
redirect("/" + "?r=" + params.r[1]);
}
}yeah, forgot it is in
rYup that worked!
But the app still doesnt work
@berkserbet But the app still doesnt work
what is not working
So I have these filters that are checkboxes, they don't update the products or show which ones are checked
On dev they do
@berkserbet Click to see attachment
you need to set the
onChange props@Ray you need to set the `onChange` props
In which file?
where is your checkbox?
In ProductCards.tsx
@berkserbet In ProductCards.tsx
I think remove the
value should do itjust passing default value to
defaultValueTrying!
Didn't seem to work
But I also have a search box and a button
None work
The work in the sense that they create a new query param, but they delete all old ones
And they don't reflect the existing ones
Checkbox is defined here:
'use client';
import { DetailedHTMLProps, InputHTMLAttributes} from "react";
export const CheckBox = (props: DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>) => {
const onClick = (e: any) => e.currentTarget.form?.requestSubmit();
return <input {...props} onClick={onClick} />
}@berkserbet Didn't seem to work
async function submitForm(formData: FormData) {
'use server';
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
redirect(`?${newSearchParams.toString()}`)
}what are you trying to do
Just keep adding query params, either by , if part of the same category or a new one
@Ray ts
async function submitForm(formData: FormData) {
'use server';
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
redirect(`?${newSearchParams.toString()}`)
}
you creating new searchParams without passing the existing
formData seemed to have it in dev
try again in dev
but I don't understand what you are trying to do here lol
@Ray try again in dev
It seems to work
<form>remove the action there and try again
But then it cant work
Then it seems to append a new query param
I want ?sizes=1,2,3
Not ?sizes=1&sizes=2
I was working on that one with DirtyCajunRice: https://nextjs-forum.com/post/1201365648538869770#message-1201455988193108038
@berkserbet Not ?sizes=1&sizes=2
async function submitForm(e: FormEvent<HTMLFormElement>) {
const formData = new FormData(e.currentTarget)
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
redirect(`?${newSearchParams.toString()}`)
}
<form onSubmit={submitForm}>trying!
@Ray ts
async function submitForm(e: FormEvent<HTMLFormElement>) {
const formData = new FormData(e.currentTarget)
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
redirect(`?${newSearchParams.toString()}`)
}
<form onSubmit={submitForm}>
On dev I see:
Error: Event handlers cannot be passed to Client Component props.
<form onSubmit={function} children=...>It should be (misspoke)
No 'use client'
add it
Sorry
I was thinking this should be a server component
Can it be?
That the whole conversion DirtyCajunRice helped me make
try to see if it work first
Sure
it was ignoring
initialParams.search right?@Ray it was ignoring `initialParams.search` right?
Yes, but also ignoring everything else
When making client I get this:
./app/ProductCards.tsx
Error:
× It is not allowed to define inline "use server" annotated Server Actions in Client Components.I have some "use server"
no
you have
'use server'; in updatePagechange it back to action
@Ray change it back to action
And remove 'use client'?
@berkserbet Didn't seem to work
so what happen when you submit the form now?
Now action is giving an error
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
<form action={function} children=...>Right now everything works on dev
what is not working in prod?
Only adds a query param to the url. Deletes all old ones. Also existing query params are not reflected on my page
It's like the data isn't coming in
could you show the url in dev and prod
Sure
This prod: http://localhost:3000/?sizes=2
But in dev things are happening on the page
In prod nothing is and it keeps overwriting
@berkserbet In prod nothing is and it keeps overwriting
what do you see in the console with this in prod
console.log("Form Data:", p, opts.join(","));Checking
Just the new selection
But the old selection isn't default checked anyway
@berkserbet Form Data: sizes 3L
async function submitForm(formData: FormData) {
'use server';
console.log(Object.fromEntries(formData))add this console.log and check it in prod
@berkserbet `{ sizes: '2' }`
Just the new selection
ok change to this
console.log(formData.getAll('sizes'))@Ray ok change to this ` console.log(formData.getAll('sizes'))`
Just the new one:
Form Data: sizes 8Data isn't coming in
@berkserbet Data isn't coming in
do you see if the checkbox is checked if
defaultChecked is true?Checking
It is checked
@Ray do you see if the checkbox is checked if `defaultChecked` is true?
When
defaultChecked={true}But it's not just checkboxes, also searchbox and button
I think you should make the form in client component
@Ray I think you should make the form in client component
But then can my page that has all the product listings access that info?
@berkserbet But then can my page that has all the product listings access that info?
you page is still a server component
and render the client form in it
and pass the data the form need
Like right now, if I manually update query params - the server component can't access all the data
It's not getting passed through
what data?
@Ray ts
import { notFound, redirect } from "next/navigation";
export default function SubredditRedirect({
params,
searchParams,
}: {
params: {r: string[]};
searchParams: { [key: string]: string };
}) {
if (params.r.length < 1) notFound()
if (searchParams) {
redirect(
"/" +
"?r=" +
params.r[1] +
"&" +
new URLSearchParams(searchParams).toString()
);
} else {
redirect("/" + "?r=" + params.r[1]);
}
}
the page receive the
searchParams object in propsWhen I go to
http://localhost:3000/?sizes=8 that sizes information should filter products - it doesn'tUnrelated to checkboxes
did you use the searchParams object?
to query your data
No I use initialParams
import React from 'react'
import ProductCards from './ProductCards';
import { ProductSearchParams } from '@/types/products';
interface Props {
searchParams: ProductSearchParams
}
export default function Home({ searchParams }: Props) {
console.log("searchParam", searchParams);
return (
<main>
<ProductCards {...searchParams} />
</main>
);
}function sanitize(params: ProductSearchParams) {
const stringsOnly = Object.fromEntries(Object.entries(params).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v]));
return {... stringsOnly, pages: Number(stringsOnly.pages)} as Record<Exclude<ProductSearchParam, 'pages'>, string> & { pages: number };
}
const ProductCards = (props: ProductSearchParams) => {
const initialParams = sanitize(props)The variable after sanitization
@berkserbet Like right now, if I manually update query params - the server component can't access all the data
what do you mean by "if I manually update query params - the server component can't access all the data"
@Ray what do you mean by "if I manually update query params - the server component can't access all the data"
I go to
http://localhost:3000/?sizes=8 but my component <ProductCards> doesn't update to reflect that sizes=8On prod
It doesn't log anything either, just static
@Ray oh it static?
I guess I can click
check the build report
But everything else loads the same
Will share build
it should tell you the route is dynamic or static
> storefront@0.1.0 build
> next build
â–² Next.js 14.1.0
- Environments: .env
Creating an optimized production build ...
🌼 daisyUI 4.6.0
├─ ✔︎ 1 theme added https://daisyui.com/docs/themes
╰─ ★ Star daisyUI on GitHub https://github.com/saadeghi/daisyui
✓ Compiled successfully
./app/ProductCards.tsx
402:31 Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
402:31 Warning: img elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
410:31 Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
410:31 Warning: img elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
./app/image.tsx
68:12 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
✓ Linting and checking validity of types
✓ Collecting page data
Generating static pages (0/6) [ ]searchParam {}
Initial Params: { pages: NaN }
Initial Params: { pages: NaN }
Current Page: 1
searchParam {}
Initial Params: { pages: NaN }
Initial Params: { pages: NaN }
Current Page: 1
✓ Generating static pages (6/6)
✓ Collecting build traces
✓ Finalizing page optimization
Route (app) Size First Load JS
┌ ○ / 6.39 kB 97.3 kB
├ ○ /_not-found 0 B 0 B
├ ○ /...not_found 141 B 84.3 kB
└ λ /[...r] 141 B 84.3 kB
+ First Load JS shared by all 84.2 kB
├ chunks/69-9c3c64001cadfd4c.js 28.9 kB
├ chunks/fd9d1056-534a3af521b04580.js 53.4 kB
â”” other shared chunks (total) 1.9 kB
â—‹ (Static) prerendered as static content
λ (Dynamic) server-rendered on demand using Node.jsok its dynamic
How can you tell?
λ (Dynamic) server-rendered on demand using Node.js
import React from 'react'
import ProductCards from './ProductCards';
import { ProductSearchParams } from '@/types/products';
interface Props {
searchParams: ProductSearchParams
}
export default function Home({ searchParams }: Props) {
console.log("searchParam", searchParams);
return (
<main>
<ProductCards key={JSON.stringify(searchParams)} {...searchParams} />
</main>
);
}But how can you tell the specific pahe?
you have only one route
Cool
Works now!
@Ray and how do you fetch the data?
I'm not sure
oh your home page is static
┌ ○ /
@Ray oh your home page is static
Is that ok?
Latest:
Route (app) Size First Load JS
┌ λ / 6.39 kB 97.3 kB
├ ○ /_not-found 0 B 0 B
├ ○ /...not_found 141 B 84.3 kB
└ λ /[...r] 141 B 84.3 kB
+ First Load JS shared by all 84.2 kB
├ chunks/69-9c3c64001cadfd4c.js 28.9 kB
├ chunks/fd9d1056-534a3af521b04580.js 53.4 kB
â”” other shared chunks (total) 1.9 kB
â—‹ (Static) prerendered as static content
λ (Dynamic) server-rendered on demand using Node.jsSo it changed
@berkserbet I go to `http://localhost:3000/?sizes=8` but my component <ProductCards> doesn't update to reflect that sizes=8
where do you render
ProductCards?In the main page
so everything work now?
it was because your home page is static generated
Yup! Quick question, my dropdowns close after each selection - is there a simple way to keep it open?
@Ray I gotta go!
Cool, thanks so much!
@Plott Hound could you help? 😆
@Ray <@578864362882727958> could you help? 😆
Can I pay for your lunch tomorrow for helping me?
@Ray <@578864362882727958> could you help? 😆
Plott Hound
Can I frame this and put it on my wall? Lol
lol
@berkserbet Yup! Quick question, my dropdowns close after each selection - is there a simple way to keep it open?
he would like the dropdown stay open
could you help with this
I gotta go lol
Plott Hound
Sure I’ll do my best!
Plott Hound
Sorry can I get a tldr while I read all of this
Later!
So I have dropdowns with checkboxes
Every time I check/uncheck - the dropdown closes
I would like the user to be able to keep selecting
Plott Hound
Ok are you using a UI library?
I use DaisyUI
And tailwind
Plott Hound
Ok gimme 1 min
Plott Hound
Does it only happen if there are checkboxes in the dropdown? Does it happen with buttons and other interactive elements?
@Plott Hound Does it only happen if there are checkboxes in the dropdown? Does it happen with buttons and other interactive elements?
I only have checkboxes in the dropdowns - but I also have a "load more..." button on the bottom of the page that scrolls to the top when I click
Plott Hound
Can you show me the code that has your checkboxes in please
@Plott Hound Can you show me the code that has your checkboxes in please
Sure, is this part enough:
<CheckBox
type="checkbox"
className="checkbox checkbox-sm"
name="conditions"
id="conditions"
value={condition}
defaultChecked={checkHandler("conditions", {condition})}
/>@berkserbet Sure, is this part enough:
ts
<CheckBox
type="checkbox"
className="checkbox checkbox-sm"
name="conditions"
id="conditions"
value={condition}
defaultChecked={checkHandler("conditions", {condition})}
/>
Plott Hound
This is really strange. I’m setting a project up to test it
Does it happen if you click an area of the dropdown that doesn’t have a checkbox?
I define CheckBox here:
'use client';
import { DetailedHTMLProps, InputHTMLAttributes} from "react";
export const CheckBox = (props: DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>) => {
const onClick = (e: any) => e.currentTarget.form?.requestSubmit();
return <input {...props} onClick={onClick} />
}@Plott Hound Does it happen if you click an area of the dropdown that doesn’t have a checkbox?
After I click a checkbox the whole page refreshes
Also after I click a button
Plott Hound
Ahhhh I see
That shouldn’t be happening, something is causing the entire page to refresh which shouldn’t be happening if you didn’t intend it to
It's a server side component
Plott Hound
This will be tricky to diagnose without looking at all of your code but essentially clicking buttons or checkboxes should not be refreshing the page
What happens when you click the checkbox? Can I see your handler function and what it calls
Sure
This check if it's checked
function checkHandler(param: ProductSearchParam, values: any) {
if (!initialParams[param] || param === 'pages') {
return false;
}
const options = initialParams[param].split(',')
switch (param) {
case "r":
return options.includes(values['subreddit_name']);
case "genders":
return options.includes(values['gender']);
case "sizes":
return options.includes(values['size']);
case "conditions":
return options.includes(values['condition']);
case "countries":
return options.includes(values['country']);
case "brands":
return options.includes(values['brand']);
default:
return false;
}
}Then I got
async function submitForm(formData: FormData) {
'use server';
console.log(formData.getAll('sizes'))
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
redirect(`?${newSearchParams.toString()}`)
}Plott Hound
It’s the redirect I think
Yeah, seems like it
Plott Hound
What are you trying to achieve with the redirect? There might be a better way
Just modifying query params
Plott Hound
I see. One sec
There’s a much better way to update the url params
Thats cool
Plott Hound
This will let you keep the page alive and avoid a hard refresh
Is it this:
replace(`${pathname}?${params.toString()}`);But that seems to be client side
Plott Hound
Yeah router is client side
I don’t think it’s possible to do it like that on the server without causing a full refresh since your manipulating the browser on the client
Yeah I think so too
How about not scrolling up during a refresh
Plott Hound
You mean a hard browser refresh? Or like router.refresh
Hard refresh
Like I don't do multiple pages
I extend the page
To show more
But user can't tell if jumps to top
Plott Hound
So it’s essentially a single page app?
It is
If I refresh my browser manually it doesn't scroll to the top
Plott Hound
It’s not a great approach to have the user needing to refresh the page to show other parts of the app especially in next. You’ll need to do it on the client
I would ideally allow infinite scroll
Plott Hound
You’d need to access the window and define a y position
But on a regular browser, if you just refresh - it keeps the y position
Plott Hound
We should really close this ticket and make a new one for this new issue.
@berkserbet But on a regular browser, if you just refresh - it keeps the y position
Plott Hound
It’s probably the redirect you’re doing
Sounds good, thanks so much!
Plott Hound
No problem
Basically redirect doesn’t have a scroll option unfortunately
Only link, router.push and router.replace do
@Plott Hound Only link, router.push and router.replace do
Sorry, quick question - could I use Link?
Plott Hound
Link is for navigating to other routes so I’m not sure how it would work given you are doing everything on a single page
Help me understand your site more. What is your app doing?
It shows product listed on reddit on a website
This is the client rendered live version
What if I just use <Link> with a prefilled link to the same page with a new query paramete
Plott Hound
You’d be much better off just invalidating the cache of your fetch when the user changes the url params
You don’t need to reroute to do what you’re trying to do
Are you using fetch?
The guide I shared earlier shows a perfect solution to your shop. I’m doing the same on my e-commerce sites
This is the function that updates the page numbers:
async function updatePage(formData: FormData) {
'use server';
console.log("Update Page.")
console.log("Form Data:", formData)
const newSearchParams = new URLSearchParams();
allSearchParams.forEach(p => {
const opts = formData.getAll(p)
if (opts.length) {
console.log("Form Data:", p, opts.join(","));
newSearchParams.append(p, opts.join(","));
}
})
if (initialParams.search) {
newSearchParams.append("search", initialParams.search)
}
newSearchParams.set("pages", ((initialParams.pages || 1) + 1).toString())
redirect(`?${newSearchParams.toString()}`)
}Plott Hound
You should try revalidatePath or revalidateTag
I'm not familiar with those
Plott Hound
When you change your search params the data will become stale because the app hasn’t been told that the data is stale so there was no need to fetch it again. If you call revalidatePath it will trigger the fetch to run again with the new parameters
Answer
Plott Hound
In a nutshell.
Cool, will do reseach. Thanks!
Closing this one
Plott Hound
Cheers
