Home > Enterprise >  Display Only 3 Objects at the time
Display Only 3 Objects at the time

Time:08-10

I have a quote generator that I am trying to implement a feature of displaying a specific amount of objects at the time. I have tried using map, but it returns that it's not a function. Right now I have it to generate a random quote, but I want to have the option to display a specific number. Any help is greatly appreciated. the is what is working, but I commented out to try out the map.

App.js

import { useState, useEffect } from "react";
import Footer from "./Components/Footer/Footer";
import Quote from "./Components/Quote/Quote";
import "./App.css"
import { data } from "./Components/Data/Data";
import { characterData } from "./Components/Data/CharacterData"
import CharacterBios from "./Components/CharacterBios/CharacterBios";
import Header from "./Components/Header/Header";

function App() {
  const [quote, setQuote] = useState();
  const [isLoading, setIsLoading] = useState(true);
  const randomise = () => {
    const randomNumber = Math.floor(Math.random() * data.length);
    setQuote(data[randomNumber]);
  };
  //math.floor makes it a whole number, and the equation above goes through the data at random
  useEffect(() => {
    randomise();
    setIsLoading(false);
  }, []);

  return (
    <div className="App">
      <Header />
      <div className="main">

      <h1>Quote Generator</h1>
      {isLoading ? <p>Quote now loading...</p> : <Quote data={quote} />}
      <button onClick={randomise}>Generate Quote</button>
      <CharacterBios characterData={characterData} />
      <Footer />
      </div>
    </div>
  );
}

export default App;

Quote.jsx

import React from 'react'


const Quote = ({data}) => {

    return (
        <div className='container quote-section'>

<div className="row">

{data.slice(0).map((item,index)=> (

    <div className="col-xl-4 col-lg-4 col-md-6 col-sm-12" key={index}> 
       
        <div className="marked-content-card">

            <p><span className="name">{item.name}</span></p>
            <p>{item.quote}</p>
        </div>
    </div>

))}



</div>

            {/* <blockquote> {
                data.quote
            }
                <p>-{
                    data.name
                }</p>
            </blockquote> */}



        </div>

    )
}

export default Quote;

CodePudding user response:

Here's what you can do:

  1. Use an array for the quote state
  2. Randomize by:
    • Cloning the quote array -> tempData = [...data]
    • Create an array to hold the quotes to be set -> tempQuotes
    • Iterate for the number of quotes you need and:
      • splice() a quote out of tempQuotes using the randome index
      • push it into tempQuotes
        • Spread ... because splice returns an array
      • Iterate again with the remaining quotes in tempData
  3. Set the new quote state
  4. Map and render

Code Sandbox

import { useState, useEffect } from "react";

const data = [
  "Another one bites the dust",
  "Sweet dreams are made of this",
  "Never gonna give you up",
  "Highway to the danger zone",
  "Let the bodies hit the floor",
  "Hey now, I'm an allstar",
  "Hello darkness my old friend"
];

function App() {
  const [quotes, setQuotes] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const numberOfQuotes = 3;

  const randomise = () => {
    const tempData = [...data];
    const tempQuotes = [];
    for (let i = 0; i < numberOfQuotes; i  ) {
      const randomNumber = Math.floor(Math.random() * tempData.length);
      tempQuotes.push(...tempData.splice(randomNumber, 1));
    }
    setQuotes(tempQuotes);
  };
  
  useEffect(() => {
    randomise();
    setIsLoading(false);
  }, []);

  const quoteEls = quotes.map((quote) => <li >{quote}</li>);

  return (
    <div className="App">
      <div className="main">
        <h1>Quote Generator</h1>
        {isLoading ? <p>Quote now loading...</p> : quoteEls}
        <button onClick={randomise}>Generate Quote</button>
      </div>
    </div>
  );
}

export default App;

CodePudding user response:

Because data[randomNumber] seems to be an object rather than an array, it will cause a problem in Quote. jsx because you treat it like an array.

Use lodash's shuffle function to randomize your array as well.

CodePudding user response:

Yes, .map is not a function because the data array contains object as per your use in the Quote component, and the reason you are getting the error is because you are setting the quote value from a value in your data array. i.e. setQuote(data[randomNumber]); as randomNumber gives an integer. You need to modify your randomise function to store a number of random quotes in your quote state:

const randomise = () => {
  const indices = new Set()
  const N = 3   // specifies number of random items
  while(true){
    const randomNumber = Math.floor(Math.random()*data.length)
    indices.add(randomNumber)
    if(indices.size>=N) break;
  }
  let quotesArr = []
  for(i in indices){
    quotesArr.push(data[i])
  }
  
  setQuote(quotesArr);
  };

Above code keep generating random numbers until you have N number of distinct random numbers, once you have that, you just need to pick the objects in data at those indices, then set the quotes.

Then you will have to update your return statement as well, specifically the part where you are using Quote component:

<>{quote.map(q => <Quote data={q} />)}</>

CodePudding user response:

Your problem essentially comes down to picking required number of random (non-repeating) quotes. So, instead of having a single quote within the App state, you have to track the array of quotes (which you will still be populating within useEffect()).

Distilled implementation of the concept might look as follows:

const { render } = ReactDOM,
      { useState, useEffect } = React,
      root = document.getElementById('root')
      
const quotesData = [
  {id: 0, name: 'me', quote: 'oranges are cool'},
  {id: 1, name: 'him', quote: 'bananas are sweet'},
  {id: 2, name: 'someone', quote: 'apples can be soar'},
  {id: 3, name: 'anyone', quote: 'I hate broccoli'},
  {id: 4, name: 'me', quote: 'pinapples are juicy'}
]

const randomQuoteMachine = (srcData, numberOfQuotes = 0) => {
  const quotes = []
  while(quotes.length < numberOfQuotes){
    const randomQuote = srcData[0|Math.random()*srcData.length]
    quotes.every(({id}) => id !== randomQuote.id) && quotes.push(randomQuote)
  } 
  return quotes
}

const Quote = ({quote}) => {
  return (
    <div>
      <h3>{quote.name}</h3>
      <p>{quote.quote}</p>
    </div>
  )
}
      
const App = () => {
  const [ quotesList, setQuotesList ] = useState([])
  
  useEffect(() => {
    const quotes = randomQuoteMachine(quotesData, 3)
    setQuotesList(quotes)
  }, [])
  
  return !!quotesList.length && (
    <div> 
      {
        quotesList.map((quote) => <Quote {...{quote, key: quote.id}} />)
      }
    </div>
  )
}   

render(
  <App />,
  root
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

  • Related