I am trying to create a score keeper component using ReactJs. I am working with vite for local server setup.My score keeper component is working but when i created a form component to add players in the score table. I see no changes in component even though the dev tools show that the prop state is changing.
The Main component where the state lives is:
import { useState } from 'react'
import ScoreKeeper from './ScoreKeeper.jsx';
import EnterFormScore from './EnterFormScore.jsx';
export default function ScoreKeeperInterFace() {
const [players,setPlayers]=useState(["Kartik","Rohit","Virat","Dhoni","Smith"]);
const addToTable=function (Name) {
setPlayers([...players,Name])
}
return (
<>
<ScoreKeeper teamNames={players} target={10}/>
<EnterFormScore add={addToTable}/>
</>
)
}
The ScoreKeeper component:
import {useState} from "react"
import {v4 as uuid } from "uuid"
import TeamScore from "./TeamScore.jsx";
import Button from "@mui/material/Button"
export default function ScoreKeeper({teamNames,target=11}){
const [winner,setWinner]=useState(false);
const [teamScores,setTeamScores]=useState(teamNames.map(e=>(
{id:uuid(),Name:e,Score:0}
)));
const IncreaseScore=(id)=>{
if(!winner)
{setTeamScores(curr=>(
curr.map((e)=>{
if(e.id===id){
if(e.Score===target-1){
setWinner({Name:e.Name,id:e.id,winner:true})
}
return {...e,Score:e.Score<target?++e.Score:e.Score}
}
else { return {...e} }
})
))
}
}
const DecreaseScore=(id)=>{
if(!winner){
setTeamScores(curr=>(
curr.map((e)=>{
if(e.id===id){
return {...e,Score:e.Score===0?0:--e.Score}
}
else { return {...e} }
})
))
}
}
const Reset=function (){
setTeamScores(curr=>(
curr.map((e)=>(
{...e,Score:0}
))
))
setWinner(false)
}
return <div className="flex flex-col items-center border rounded-md w-[fit-content] h-auto px-3 pt-3 shadow bg-slate-400">
{winner.winner && <h1>The Winner is: {winner.Name}</h1>}
<div className="flex space-x-1">{teamScores.map(e=>(
<TeamScore inc={()=>{ IncreaseScore(e.id)}} dec={()=>{DecreaseScore(e.id)}} Name={e.Name} Score={e.Score}/>
))}
</div>
<Button onClick={Reset}>Reset</Button>
</div>
}
EnterFormScore component is:
import { useState } from "react"
import Button from "@mui/material/Button"
export default function EnterFormScore({add}){
const [player,setPlayer]=useState("");
const ControlForm=function (e){
setPlayer(e.target.value);
}
return(
<div>
<input id="player_name" value={player} placeholder="Player Name" onChange={ControlForm}/>
<Button onClick={() =>{ add(player)}}>Add To The Table</Button>
</div>
)
}
I have used tailwindCss and material UI also in this component. Please give me some insights i am unable to find a solution to it.
2
Answers
I think the problem is that your
ScoreKeeper
component is not re-rendering because you’re missing auseEffect
inside the component.The mapping of the
teamNames
insideuseState
is just running on initial render.I’d initialize the
teamScores
state with an empty array and then add the followinguseEffect
toScoreKeeper
component:What is it doing?
It checks if the team is already in the
teamScores
array, if not it will update the list with the new team. It’s checked by name, would be better to check by id but there is no id (see comment below).Some notes to your code:
name
ornewTeamNames
uuid
in the top-level so you can use it later to identify your teams (not changed in the snippet)I haven’t thought about your data structure but fixed your issue.
You can find the complete demo here
Full Code below (not working here):
You can try giving a key value to the component that you want to re render. Because when the component key change, the component will be rendering again.
Example:
if you change the refresh value, it will be re rendering.