I’m tring to make a search bar in NEXT.JS
the SearchBar component uses router to redirect to the search page with a searchParams
the search page uses the searchParams to call an api endpoint to search fo the products and return a JSON object , then set the state inside the search page to the data received.
the fetchHandler is called inside a useEffect hook with an empty dependecy array.
The error: somehow the page stuck in render loop where the useEffect keeps setting the state and the page keep rendering and triggering the useEffect hook !!!,
i’ve checked the api and it is only being called once , there’s only warning about experimental features and a missing key in a list (that was struggling to locate ) but that didn’t effect anything before .
this pattern is working alright for me in another page, but somehow it’s not in this case,
Am I missing something here or should i look somewhere else?
the search bar:
'use client'
import React from 'react'
import { useState, useRef } from "react";
import {v4 as uuidv4} from 'uuid';
import { useRouter } from 'next/navigation';
const SearchBar = () => {
const router = useRouter();
const inputRef = useRef();
const handleChange = (e) => {
inputRef.current = e.target.value;
}
const handleClick = async (e) => {
if(!inputRef.current)return;
// names in the database are all hyphen sepratedlo
const searchQuery = inputRef.current.trim().split(' ').join('-');
if(!searchQuery)return;
router.push(`/searchquery?q=${searchQuery}`)
}
return (
<div key={uuidv4()} className='w-72 h-10 bg-white flex-row-between shadow rounded-2xl p-1'>
<button onClick={e => handleClick(e)} >
<img src="/assets/icons/search.png" alt="search" className='w-5 h-5 m-1' />
</button>
<input type="text" className='w-5/6'
onChange={ e => handleChange(e)}
/>
</div>
)
}
export default SearchBar
the search page:
'use client';
import {useState, useEffect} from "react";
async function searchquery({searchParams}) {
const [products, setProducts] = useState([]);
console.log("🚀 ~ file: page.jsx:7 ~ searchquery ~ products:", products)
const fetchHandler = async () => {
try {
const query = searchParams.q;
const res = await fetch(`/api/query`,{
method: 'POST',
body: JSON.stringify({query: query})
})
const data = await res.json()
if (!res.ok)
throw new Error(data.error || 'Something went wrong')
setProducts(data.products)
} catch (e) {
setError(e.message)
}
}
useEffect(() => {
fetchHandler()
}, [])
return (<div>query</div>)
}
export default searchquery
the api endpoint:
import { connectToDB } from '@utils/database';
import { Product } from '@utils/productModel';
import { NextResponse } from 'next/server';
export async function POST(request) {
try {
const res = await request.json();
const namePart = res.query.split(' ').join('-')
const query = { name: { $regex: namePart, $options: 'i' } };
await connectToDB();
const products = await Product.find(query);
return NextResponse.json({products})
} catch (error) {
console.log(error);
return NextResponse.json({ error: error.message })
}
}