Víctor Donat
Víctor Donat

Reputation: 47

How sort rendering of products by value?

I have array of objects products like

[{name: 'apple', value: 100}, {name: 'watermelon', value: 200}, {name: 'orange', value: 50}], and a select input with "High price" and "Low price" options, but it doesn't works:

function ProductsPage() {
    const [products, setProducts] = useState([])

    useEffect(() => {/*here i setProducts([...]) array of objects which i get of backend*/})

    const orderShowing = (e) => {
        let actual_show = products
        let newOrder = e.target.value;
        if (newOrder === "High price") {
            actual_show.sort((a, b) => (b.value > a.value) ? 1 : (a.value > b.value) ? -1 : 0)
        } else if (newOrder === "Low price") {
            actual_show.sort((a, b) => (a.value > b.value) ? 1 : (b.value > a.value) ? -1 : 0)
        console.log(actual_show)
        setProducts(actual_show)
    }

    return (
        <div>
            <select id="productsOrder" onChange={orderShowing}>
                <option>High price</option>
                <option>Low price</option>
            </select>
            <h2>Products</h2>
            {products.map((p) => {
                return <p>{p.name}</p>})}
        </div>
    )
}

the console.log actually is what i want (the sort works), but the page don't refresh with the 'new' products array

Upvotes: 3

Views: 158

Answers (4)

Rukshan Jayasekara
Rukshan Jayasekara

Reputation: 1985

Here's the working example with minimum changes to the existing code. Run the code here

export default function App() {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    setProducts([
      { name: 'apple', value: 100 },
      { name: 'watermelon', value: 200 },
      { name: 'orange', value: 50 }
    ]);
  }, []);

  const orderShowing = e => {
    let actual_show = products.slice(); //making a copy of products
    let newOrder = e.target.value;
    if (newOrder === 'High price') {
      actual_show.sort((a, b) =>
        b.value > a.value ? 1 : a.value > b.value ? -1 : 0
      );
    } else if (newOrder === 'Low price') {
      actual_show.sort((a, b) =>
        a.value > b.value ? 1 : b.value > a.value ? -1 : 0
      );
    }
    console.log(actual_show);
    setProducts(actual_show);
  };
  return (
    <div>
      <select id="productsOrder" onChange={orderShowing}>
        <option>High price</option>
        <option>Low price</option>
      </select>
      <h2>Products</h2>
      {products.map(p => {
        return <p>{p.name}</p>;
      })}
    </div>
  );
}

Upvotes: 1

Majid M.
Majid M.

Reputation: 4974

First you need to make a copy of your state:

  let actual_show = [...products];

Then try to sort it like I'm using :

import { useEffect, useState } from "react";

export default function App() {
  const [products, setProducts] = useState([
    { name: "apple", value: 100 },
    { name: "watermelon", value: 200 },
    { name: "orange", value: 50 }
  ]);

  const orderShowing = (e) => {
    let actual_show = [...products];
    let newOrder = e.target.value;
    if (newOrder === "High price") {
      actual_show.sort((a, b) => a.value - b.value);
    } else if (newOrder === "Low price") {
      actual_show.sort((a, b) => b.value - a.value);
    }
    setProducts(actual_show);
  };

  return (
    <div>
      <select id="productsOrder" onChange={orderShowing}>
        <option>High price</option>
        <option>Low price</option>
      </select>
      <h2>Products</h2>
      {products.map((p) => {
        return <p>{p.name}</p>;
      })}
    </div>
  );
}

Edit gracious-darkness-gjk6k

Upvotes: 3

sickenWings
sickenWings

Reputation: 1

I ran your code. You just forgot the curly braces on p.name when you mapped it - it will be treated as a string otherwise. It should be {p.name}.

Upvotes: 0

CodeByZach
CodeByZach

Reputation: 11

Try something like this:

products.sort(function (a, b) {
  return a.value - b.value;
});

Keep in mind this solution will only work since the values are numeric.

Upvotes: -1

Related Questions