0

I have an array and I would like to display one item from the array at random within my render function. Here's what I have now which shows all items:

render() {
    return (
        <article className="rand-product-cont">
            {this.state.products && this.state.products.map((product, index) => (
            <article key={index} className="rand-product">
                <h3>"{product.name}"</h3>
            </article>
            ))}
        </article>
    );
};

How can I modify this to show only one product from the array at random? I tried this based on another question I found but it seems to display the same product every time:

render() {
    const product = this.state.products.sort(() => Math.random() - Math.random()).slice(0, 1);
    return (
        <article className="rand-product-cont">
            {product && product.map((product, index) => (
            <article key={index} className="rand-product">
                <h3>"{product.name}"</h3>
            </article>
            ))}
        </article>
    );
};
user13286
  • 3,027
  • 9
  • 45
  • 100
  • 3
    Does this answer your question? [Getting a random value from a JavaScript array](https://stackoverflow.com/questions/4550505/getting-a-random-value-from-a-javascript-array) – djfdev Dec 13 '19 at 21:11
  • 2
    If you just want one value, then `.map()` should not be involved. – Pointy Dec 13 '19 at 21:17

2 Answers2

4

Your random generator works like charm. The issue is how you render the product what your code picked from products array.

Try the following without map:

render() {
    const product = this.state.products.sort(() => Math.random() - Math.random())
                                       .find(() => true);

    return (
        <article className="rand-product-cont">
            {product &&
                <article className="rand-product">
                    <h3>"{product.name}"</h3>
                </article>
            }
        </article>
    );
};

The above solution is using similar approach what I have here, representing products array with only number values, find returns the first element, so you don't need to use indexer on products array:

const array = [12,23,43,45,34,22,77];
const element = array.sort(() => Math.random() - Math.random())
                     .find(() => true);

console.log(element);

I hope this helps!

norbitrial
  • 14,716
  • 7
  • 32
  • 59
  • 2
    Thank you, I think this is close to what I need. However when I do this nothing is being displayed and I think it's because `product` is still an array with one item. Can I just do `{product[0].name}`? – user13286 Dec 13 '19 at 21:22
  • 2
    That's true, `sort` returns an array. Let me update my answer. – norbitrial Dec 13 '19 at 21:23
  • 1
    @user13286 I have change a bit, removed `slice` and added `find` method which gives you back the first product from the sorted array. – norbitrial Dec 13 '19 at 21:29
  • Something strange I noticed is that when I resize my browser window, the random product that is being displayed is changing in real-time. Is there a way to prevent that from happening? The page should pick a single product at random on load and it should continue displaying that same product until the page is reloaded. – user13286 Dec 16 '19 at 02:56
1

If you need only one element and if it's going to be random. I don't see point of using map at all

  function getRandomElFromArray(arrayLenght) {
    return Math.floor(Math.random() * arrayLength);
  }

  <article ...
    {
      product && product.length > 0 &&
      product[getRandomElFromArray(product.length)]
    }
  </article>

Ertan Kara
  • 308
  • 3
  • 12