I'm using next.js for online shop project and I have a page that shows best selling lots (bestSellings.tsx). In this page there is a select box that sorts the lots ordering by different factors and each factor has an unique value:
<select name="ec-select" id="ec-select" onChange={changeSelectBox}>
<option value="1" selected={false} disabled={false}>state</option>
<option value="2" >name,asc</option>
<option value="3">name,dec</option>
<option value="4">price,asc</option>
<option value="5">price,dec</option>
</select>
I want to pass query for each type of sorts, for example when user click option value='2' It must go to :'bestSellings/sort=2' so I defined changeSelectBox function:
const changeSelectBox=(e:React.ChangeEvent<HTMLSelectElement>)=>{
const value=e.target.value
router.push({pathname:`/bestSelling/`,query:{...query,sort:value}})
}
Everything was ok until I tried to change lotsInBestSelling array to sorted array by changing the query. This is the whole page:
const BestSelling = ({query}:{query:any}) => {
const [lotsInBestSellings,setLotsInBestSellings]:any=useState([])
//to sort array
const sortArray=(array:any[],property:any,dec:boolean)=>{
console.log('s')
console.log(typeof property)
const compare=(a:any,b:any)=>{
if(typeof a[property] ===`string`){
console.log('string')
if (dec==false){
return a[property].localeCompare(b[property])
}
else{
return b[property].localeCompare(a[property])
}
}
else{
if (dec==false){
console.log('number')
return a[property]-b[property]
}
else{
return b[property]-a[property]
// if(a[property]<b[property]){
// return 1
// }
// else if(a[property]>b[property]){
// return -1
// }
// return 0
}
}
}
array=array.sort(compare)
return array
}
const initializeLotsInBestSelling=async()=>{
if(query!=undefined){
if(query.sort!=undefined){
const sort=query.sort
//cases of sorts
var sortedArray=[...lotsInBestSellings]
switch (sort){
case `1`:
break;
case `2`:
console.log(`2`)
sortedArray=await sortArray(`title`,false)
break;
case `3`:
sortedArray=await sortArray(`title`,true)
break;
case `4`:
sortedArray=await sortArray(`price`,false)
break;
case `5`:
sortedArray=await sortArray(`price`,true)
break;
}
setLotsInBestSellings([...sortedArray])
}
}
}
//to get bestSelling from API
const bestSellings=async()=>{
try{
const lots =await getBestSellings();
console.log(lots)
setLotsInBestSellings(lots)
}
catch(er){
console.log(er)
}
}
}
useEffect(()=>{
console.log("ue")
bestSellings();
initializeLotsInBestSelling();
setTimeout(()=>changeLoading(false),4000)
},[loading,lotsInBestSellings])
return(<>
{console.log(lotsInBestSellings)}
<select name="ec-select" id="ec-select" onChange={changeSelectBox}>
<option value="1" selected={false} disabled={false}>state</option>
<option value="2" >name,asc</option>
<option value="3">name,dec</option>
<option value="4">price,asc</option>
<option value="5">price,dec</option>
</select>
{ lotsInBestSellings.length!=0 && (lotsInBestSellings.map((el:any,i:number)=>{
return (
<div key={el.id} className={`col-lg-4 col-md-6 col-sm-6 col-xs-6 mb-6 pro-gl-content ${listStyle==true? "width-100":" "}`}>
<div className="ec-product-inner">
<ReactLoading key={i} height={"10vh"} width={'10vw'} color={"#3474d4"}/>
</div>
</div>
)
}))}
</>)
The problem is when I change query and then change lotsInBestSelling, I have the old and unsorted version of lotsInBestSelling. When I logged in useEffect I discovered that useEffect runs only one time and it didn't run when the query changes! I just want page to be refreshed when the user changes type of sort and as It's not a dynamic route I think it's not professional to use getStaticProps or getServerSideProps.
Well, I solved my problem by correcting some mistakes:
1- acording to julio's comment I forgot passing first parameter to sortArray function(I should pass an array as the first argument), so I changed initializeLotsInBestSelling() function(notice the sortArray function) and this is changed area:
const initializeLotsInBestSelling=async()=>{
if(query.sort!=undefined){
const sort=query.sort
//cases of sorts
console.log(lots)
sortedArray=lots
switch (sort){
case `1`:
break;
case `2`:
console.log(`2`)
sortedArray=await sortArray(lots,`title`,false)
break;
case `3`:
sortedArray=await sortArray(lots,`title`,true)
break;
case `4`:
sortedArray=await sortArray(lots,`price`,false)
break;
case `5`:
sortedArray=await sortArray(lots,`price`,true)
break;
}
console.log([...sortedArray])
setLotsInBestSellings([...sortedArray])
}
}
2-I used query as a peace of prop ({query}), so query was empty. In static routes like this we should get query using router.query
so I changed query:
query=router.query
3-After user changed the option of the selectBox, the page was routing to page with query. but lotsInBestSellings didn't change anymore. so it was necessary to initializeLotsinBestSelling when changeSelectBox function is triggered. so I changed changeSelectBox() function to :
const changeSelectBox=(e:React.ChangeEvent<HTMLSelectElement>)=>{
changeLoading(true)
const value=e.target.value
await initializeLotsInBestSelling();
router.push({pathname:`/bestSelling/`,query:{...query,sort:value}})
}
Now I don't need to add [lotsInBestSellings] at the and of the useEffect.