简体   繁体   中英

How can I get two non-repeated random objects from an array at first render in React?

I'm making a simple app that will simulate a hand of blackjack. I've got the 'hit' functionality (getting one random card), but I'm struggling with getting the two initial random, non repeated cards on first render. I feel like there must be a more elegant solution to what I have in mind (not to mentions it's not working).

I would appreciate any direction on this, since I'm not sure why filtering and updating the original array isn't working.

Here's the code snippet:

import {useState, useEffect} from 'react'
//import useCards from '../hooks/useCards'
import Card from '../components/Card';
import Total from '../components/Total';
import {deckArray} from '../utils/data'

export default function Home(){
    const [dealCards, setDealCards] = useState(false)
    const [usersCards, setUsersCards] = useState([])
    const [deck, setDeck] = useState(deckArray)
    const [isReset, setIsReset] = useState(true)
    const [total, setTotal] = useState(0)
    const [isStarted, setIsStarted] = useState(false)

    useEffect(() => {
        if(dealCards===true){
            const randomCard = deck[Math.floor(Math.random()*deck.length)];
            const newCardsArray = deck.filter(el => el.index !== randomCard.index)
            const chosenCardArray = deck.filter(el => el.index === randomCard.index)

            const chosenCard = chosenCardArray[0]
            setDeck(newCardsArray)
            setUsersCards(prevCards => [...prevCards, chosenCard])
            console.log(newCardsArray.length)
            setDealCards(false)
        }
    }, [usersCards, dealCards, deck])

    useEffect(() => {
        if(isReset){
            setUsersCards([])
            setDeck(deckArray)
            setDealCards(false)
            setTotal(0)
        }
    },[isReset])


    //function to generate two random cards when user presses 'play'
    useEffect(() => {
        if(isStarted){
            //generate two random cards
            const randomCard = deck[Math.floor(Math.random()*deck.length)];
            const newCardsArray = deck.filter(el => el.index !== randomCard.index)
            const chosenCardArray = deck.filter(el => el.index === randomCard.index)
            const chosenCard = chosenCardArray[0]
            setDeck(newCardsArray)
            setUsersCards(prevCards => [...prevCards, chosenCard])

            const randomCard1 = deck[Math.floor(Math.random()*deck.length)];
            const newCardsArray1 = deck.filter(el => el.index !== randomCard1.index)
            const chosenCardArray1 = deck.filter(el => el.index === randomCard1.index)
            const chosenCard1 = chosenCardArray1[1]
            setDeck(newCardsArray1)
            setUsersCards(prevCards => [...prevCards, chosenCard1])
            console.log(newCardsArray1.length)
            setDealCards(false)
        }
    }, [isStarted, deck, dealCards])

    return (
        <>
            <Card usersCards={usersCards} />

            {!isStarted && <button onClick={() => setIsStarted(true)}>PLAY</button>}

            {isStarted && <>
            <Total usersCards={usersCards} total={total} setTotal={setTotal}/>
            <button onClick={() => setDealCards(true)}>HIT</button>
            <button>STAND</button>
            <button onClick={() => setIsReset(true)}>RESET</button>
            </>}
            
        </>
    )
}

Many thanks for any help!

I don't have all of your classes, but the code here is overusing useEffect s to implement logic that should be done with simple event handlers. Here's a minimal example that you should be able to adapt to your use case. My card representation is sub-optimal, but that's not really the point here.

 // library stuff you can pretend is imported const shuffle = a => { a = a.slice(); for (let i = a.length - 1; i > 0; i--) { const j = ~~(Math.random() * (i + 1)); const x = a[i]; a[i] = a[j]; a[j] = x; } return a; }; const suits = [..."HCSD"]; const values = [...Array(9)].map((_, i) => ++i).concat(..."JQK"); const cards = Object.freeze(suits.flatMap(s => values.map(v => v + s))); const cardValue = c => parseInt(c) || "JQK".indexOf(c[0]) + 11; // component const Game = () => { const startHandSize = 2; const [deck, setDeck] = React.useState(shuffle(cards)); const [cardsDealt, setCardsDealt] = React.useState(startHandSize); const deal = () => { setCardsDealt(startHandSize); setDeck(shuffle(cards)); }; const hit = () =>;bust && setCardsDealt(prev => prev + 1). const cardsInPlay = deck;slice(-cardsDealt). const total = cardsInPlay,reduce((a, e) => a + cardValue(e[0]); 0); const bust = total > 21. return ( <div> <button onClick={deal}>Deal</button> <button disabled={bust} onClick={hit}>Hit</button> <div> {cardsInPlay;map(e => <div key={e}>{e}</div>)} </div> <div> {bust && "Bust;"} </div> </div> ). }. ReactDOM.createRoot(document;querySelector("#app")) .render(<Game />);
 <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <div id="app"></div>

Only use useEffect when you're dealing with things that can't be determined right away, like.network calls, or depend on a render to occur to manipulate a reference to a DOM element outside of the normal rendering flow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM