1

I'm working with a search functionality and getting the correct data from page1, which is 2 sets of Array of data (like what you can see on the photo), but the problem is when I pushed it my page2 using router, it showed only 1 data. Do I miss something with my code? Thank you in advance.

enter image description here

Page1.js

import React, {useState} from "react"
import Router, { useRouter } from "next/router"

function PropertyList() {
const [searchInput, setSearchInput] = useState("");
const [property, setProperty] = useState([]);
const router = useRouter();

const fetchPropertiesInfo = async () => {
const api_token = process.env.NEXT_PUBLIC_API_TOKEN

const response = await fetch(`dummy/api/filter?term=${searchInput}`, {
  method: 'GET',
    headers: {
    'Authorization': 'Bearer ' + api_token,
    'Content-Type': 'application/json',
    'Accept': "application/vnd.v1+json"
  }
})
const data = await response.json()
setProperty(data.properties)
}
{
  property.map((property) => {
    router.push({
      pathname: "/PageTwo",
      query: {
        id: property.id,
        name: property.name,
      }
    }, undefined, { shallow: false }, '/PageTwo')
    // {console.log(property.id)}
    // {console.log(property.name)}  
  })
}
return (
<>
<div className="pt-24">
  <div className="flex justify-center items-center">
    <input onChange={(e) => setSearchInput(e.target.value)} type="text" className="p-2 border border-primaryOrange" />
    <button onClick={fetchPropertiesInfo} className='bg-primaryOrange text-white rounded-sm p-2'>Search</button>
  </div>
  <h1>List of Properties</h1>
</div>
</>
)
}

export default PropertyList

Page2.js

import Router, { useRouter } from 'next/router';

function displayResults() {
const router = useRouter();
const { id, name } = router.query;

return (
<>
  {
    <div key={id} className='py-40 flex justify-center items-center'>
    <p>{id}</p>
    <h1>{name}</h1>

  {
    console.log(id)
  }
  {   
    console.log(name)
  }
  </div>
  }
</>
)
}

export default displayResults
Whiz
  • 33
  • 6

2 Answers2

0

It looks like you are passing the elements/objects in the array iteratively to the query parameter instead of the whole array. So, when the first iteration of the properties.map is carried out, the router pushes to the next page with the first element in the array. The rest of the elements are ignored.

What you can do is push the array in the query params when you have required length of objects in the array.

router.push(
    {
      pathname: "/PageTwo",
      query: property.reduce(
        (acc, cur, index) => ({
          ...acc,
          [`id_${index}`]: cur.id,
          [`name_${index}`]: cur.name,
        }),
        {}
      ),
    },
    undefined,
    { shallow: false },
    "/PageTwo"
  );

This will push the whole array and its objects in the query params which can be deconstructed in PageTwo.

localhost:3000?id_0:foo&name_0=bar&id_1:fooid&name_1:barname

Alternatively, if the number of elements in the property array is too long which will make the url too long, you can store the array in cookies as cookies will persist between page transitions in Nextjs.

RobLjm
  • 399
  • 2
  • 11
  • I tried the first solution, but the colons cause an error, say ';' unexpected and when try to change into semicolon it throws this error "No router instance found. you should only use "next/router" inside the client side of your app" – Whiz Sep 18 '22 at 03:14
  • @Whiz I have updated the answer using [Reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method. This will solve the issues. The previous answer was returning an array for `query` parameter. The updated answer now returns an object. – RobLjm Sep 19 '22 at 06:16
  • Thank you for your help but using reduce is not applicable to what I what to achieved so I decided to make a different approach. – Whiz Sep 20 '22 at 01:14
0

I have already fixed my problem by passing the keyword from page 1 to page 2 and fetch the data on load function using useEffect. I'm not sure if it is a good approach but it's working fine now, and the great thing is I can move forward. Here is my solution.

PageOne.js

import React, {useState} from "react"
import Router, { useRouter } from "next/router"

function PropertyList() {
const [searchInput, setSearchInput] = useState("");
const router = useRouter();

const search = () => {
router.push({
pathname: "/PageTwo",
query: {
  location: searchInput,
}
})
}

return (
<>
<div className="pt-24">
  <div className="flex justify-center items-center">
    <input onChange={(e) => setSearchInput(e.target.value)} type="text" className="p-2 border border-primaryOrange" />
    <button onClick={search} className='bg-primaryOrange text-white rounded-sm p-2'>Search</button>
  </div>
  <h1>List of Properties</h1>
</div>
</>
)
}
export default PropertyList

PageTwo.js

import Router, { useRouter } from 'next/router';
import React, {useState, useEffect} from 'react';

function displayResults() {
const router = useRouter();
const { location } = router.query;
const [property, setProperty] = useState([]);

const fetchPropertiesInfo = async () => {

const api_token = process.env.NEXT_PUBLIC_API_TOKEN

const response = await fetch(`dummy/api/filter?term=${location}`, {
  method: 'GET',
    headers: {
    'Authorization': 'Bearer ' + api_token,
    'Content-Type': 'application/json',
    'Accept': "application/vnd.v1+json"
  }
})
const data = await response.json()
setProperty(data.properties)
};

useEffect(() => {
fetchPropertiesInfo(); 
}, [`${location}`]);

console.log(property)
}
return (
<>
    <div className='py-40 flex flex-col justify-center items-center'>
      <h1 className='capitalize'>{location}</h1>
      <input type="text" className='border border-primaryOrange' />
    </div>
</>
)
export default displayResults
Whiz
  • 33
  • 6