Home > Enterprise >  React/Typescript: How to trigger function on one element when clicking on a different one?
React/Typescript: How to trigger function on one element when clicking on a different one?

Time:11-05

I´m coding a mini game where two hamster pictures fight to see who´s cutest.

Everytime the user clicks on the winning picture, I need to update in my database the number of wins/defeats for each hamster object competing in that match.

I'm completely lost on how to trigger the updateDefeats function on the losing hamster object though, the one that hasn't been clicked.

Here is my code:

import { useEffect, useState } from 'react';
import { Hamster } from '../../models/Hamster';
import FighterCard from './FighterCard'
import '../../styles/game.css'

type Hamsters = Hamster;

const baseUrl = 'http://localhost:1337';

const Game = () => {

    const [fighters, setFighters] = useState<Hamsters[] | null>(null)
    

    useEffect(() => {
        getFighters(setFighters)
    }, [])

    function newGame() {
        getFighters(setFighters)
    }


    function updateWin(id: string, wins: number, games: number) {
        const newWins = wins   1;
        const newGames = games   1;

        return fetch(baseUrl   '/hamsters/'   id, {
        method: 'PUT',
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({wins: newWins, games: newGames})
        })
        
    }

    function updateDefeats(id:string, defeats: number, games: number) {
        const newDefeats = defeats   1;
        const newGames = games   1;

        return fetch(baseUrl   '/hamsters/'   id, {
        method: 'PUT',
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({defeats: newDefeats, games: newGames})
        })
        
    }
    

    return (
        <div className='game'>
            <h2>Let the fight begin!</h2>
            <p>Click on the cutest hamster</p>

            <section className="fighters">
                {fighters
                ? fighters.map(fighter => (
                    <FighterCard fighter={fighter} key={fighter.id} updateWin={updateWin}/>
                ))
                : 'Loading fighters...'}
            </section>

            <button onClick={newGame}>New Game</button>

        </div>
    )
};



async function getFighters(saveFighters: any) {
    const response = await fetch(baseUrl   '/hamsters');
    const data = await response.json()
    const fighters = await data.sort(() => .5 - Math.random()).slice(0,2)
    saveFighters(fighters)
};

export default Game 

Anyone can help me? Thanks in advance :)

CodePudding user response:

Sorry for the lack of TS, but it won't take you much to add typings ;). You could create a fighters dependant callback and just put this into your onClick instead:

const concludeTheFight = useCallback((winningFighter, ...) => {
  const winningFighterFilter = fighter => fighter !== winningFighter
  const defeatedFighters = fighters.filter(winningFighterFilter)
  const defeatUpdates = defeatedFighters.map(updateDefeats)
  const winUpdate = updateWin(winningFighter)

  // if you need the responses to update your fighters:
  const defeatResponses = await Promise.all(defeatUpdates)
  const winResponse = await winUpdate
  // I think you will figure out how to deal with them by yourself :)
}, [fighters])

CodePudding user response:

If there are only ever two hamsters, then you know the loser must be the one who didn't win. So you can just have a small controller function that takes the id of the hamster who won, and calls updateWin and updateDefeat.

function updateWinnersAndLosers = (winnerId: string) => {
   const winner = fighters.find(fighter => fighter.id === winnerId);
   const loser = fighters.find(fighter => fighter.id !== winnerId);
   updateWin(winner.id, winner.wins, winner.games);
   updateDefeat(loser.id, loser.defeats, loser.games);
}

...
/*inside your fighters.map */
<FighterCard fighter={fighter} key={fighter.id} updateWin={updateWinnersAndLosers}/>

If you eventually end up having a 3 hamster fight, you can switch to something like

const losers = fighters.filter(fighter => fighter.id !== winnerId);
losers.forEach(loser => updateDefeat(loser.id, loser.defeats, loser.games))
  • Related