(lt.50) Master React State Hook, Keys, and Props with a Tic-Tac-Toe Project Tutorial
Introduction
The useState hook is one of the most fundamental hooks in React. The useState hook is a powerful tool for managing state in functional components, making your code more concise and easier to read. By using useState, you can efficiently manage component state without needing to convert to class components.
Coding demonstration will help it to understand better
Code:
we will import 'useState' hook from react library
Counter.js file:
import {useState} from 'react';
// //useState is a in built react keyword
let a = 20;
// we havr to make state variable because react only renders the state variables
function Counter()
{
// usestate will return a array
const [x , setX] = useState(0);
const [y , sety] = useState(0);
return(
<>
count X: {x}
{/* just like in html we cant here define class normally we have to use camel case or any other method but the convention one */}
{/* please remember dont give unnecessary spaces between the variable or statements like x = x +1
it may lead to error instead write x=x+1 */}
<button onClick={ () => setX(x+1)}>Inc</button>
<button onClick={ () => setX(x- 1)}> Dec</button>
<br />
count Y: {y}
<button onClick={ () => sety(y+1)}>Inc</button>
<button onClick={ () => sety(y- 1)}> Dec</button>
Count a = {a}
<button onClick={ () => (a =a+1)}>Inc</button>
</>
)
}
export default Counter;
App.js
import DogCard, { Image } from "./DogCard";
import Counter from "./Counter";
function App()
{
return(
<div>
<Counter/>
</div>
);
}
export default App;
State Variable
The useState return an array.
const [count, setCount] = useState(0);
count: The state variable that holds the current value, in this case, initialized to 0.
setCount: A function that updates the state variable count.
Updating State:
- The state is updated by calling the setCount function with the new state value.
Conditional rendering and lists
Conditional rendering in React works the same way conditions work in JavaScript. You can use JavaScript operators like if
, else
, and ternary operators to conditionally render elements.
import { useState } from "react";
function Counter() {
const [x, setX] = useState(0);
return (
<>
count X: {x} is {( x % 2 == 0) ? 'Even' : "odd"}
<button onClick={() => setX(x + 1)}>Inc</button>
<button onClick={() => setX(x - 1)}> Dec</button>
</>
);
}
export default Counter;
Some examples of props
//app.js
// // code for props
import './App.css'
import Avatar from './Avatar'
function App(){
// we can make a object and directly send it acting a promp in avatar
const obj ={
src: "https://t4.ftcdn.net/jpg/06/02/74/39/360_F_602743936_qbTuk7bb34cSYBgSDbsirlmJSbxRBUFM.jpg",
width: "250px",
height: "200px"
}
return (
<>
{/* <Avatar>
<Avatar {...obj}
/>
<Avatar
src ="https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Labrador_Retriever_portrait.jpg/1200px-Labrador_Retriever_portrait.jpg"
width ="450px"
height ="400px"
/>
<Avatar
src ="https://images.ctfassets.net/440y9b545yd9/6XiOUMAXyH2O6afLHzmhHb/fcbd7273587541de814c21360fb2fe49/27labinfield.jpg"
width ="450px"
height ="400px"
/> */}
{/* <Avatar
src1 ="https://lh3.googleusercontent.com/ePNrTR5PmGEgH9Nt0wmpZztcnG9QgxhhjLhnrXQjnburUunXUK1OKaOTnQ4DYO874kd-43xbbeRzpX-MFL5K1TiIJuMgvWBEVo6o9kZkvg=s750"
width1 ="400px"
height1 ="300px"
/> */}
<Avatar
src="https://lh3.googleusercontent.com/ePNrTR5PmGEgH9Nt0wmpZztcnG9QgxhhjLhnrXQjnburUunXUK1OKaOTnQ4DYO874kd-43xbbeRzpX-MFL5K1TiIJuMgvWBEVo6o9kZkvg=s750"
width="400"
height="300"
>
<span>
Child tag
</span>
</Avatar>
</>
)
}
export default App
Avatar.js
// function Avatar(props)
// {
// return(
// <>
// <img src={props.src} width ={props.width} height ={props.height}/>
// {/* <img src={props.src} width ={props.width} height ={props.height}/> */}
// {/* <img src={props.src1} width ={props.width1} height ={props.height1}/> */}
// </>
// )
// }
// export default Avatar;
// // // sometimes we dont want to use props.src to minimize the code in that case we can directly destructure the props
// to access the span tag we have to use special promp
function Avatar({src , width , height , child})
{
return(
<>
<img src={src} width ={width} height ={height}/>
{child}
</>
)
}
export default Avatar;
Conditional rendering and list rendering are powerful features in React that allow you to create dynamic and flexible user interfaces. By understanding how to use if-else
statements, ternary operators, logical operators, and the map function, you can efficiently manage and display complex data in your React applications.
key prop
The key prop is a special attribute in React that helps to identify which items in a list have changed, been added, or removed. It's a crucial part of rendering lists in React efficiently
App.js
import React from 'react';
function ListItem({ value }) {
return <li>{value}</li>;
}
function NumberList({ numbers }) {
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
)}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
function App() {
return (
<div>
<NumberList numbers={numbers} />
</div>
);
}
export default App;
The key
prop is essential for helping React to optimize rendering performance and correctly identify elements in a list. Always ensure that your keys are unique and stable to avoid potential bugs and inefficiencies in your application.
A small project from whatever we learned
Creating a game
make a folder named : tic-tac-toe
install : vite using react and JavaScript
run this : npm install react-icons --save
now go to current folder and lets start making files
remove all the CSS file items
the below picture will help you know how i created folders and files
Grid.jsx
import { useState } from "react";
import Card from "../Card/Card";
import './Grid.css'
import isWinner from "../../Helpers/Checkwinner";
function Grid({ numberOfcards }) {
const [turn, setTurn] = useState(true)
// const[x,y] -> this is called state variable
const [b, setBoard] = useState(Array(numberOfcards).fill(""));
const[winner , setWinner] = useState(null)
function play(index)
{
if(turn == true)
{
b[index] ='0'
}
else
{
b[index ] ='x'
}
const win = isWinner(b , turn ? '0' :"x")
if(win)
{
setWinner(win)
}
setBoard ([...b])
setTurn(!turn)
}
function reset(){
setTurn(true)
setWinner(null)
setBoard(Array(numberOfcards).fill(""))
}
return (
<div className="grid-wrap">
{
winner && (
<>
<h1 className="turn-highlight">winner is {winner}</h1>
<button className="reset" onClick={reset} >Reset game</button>
</>
)
}
<h2 className="turn">Current Turn :{( turn)? '0' : 'x'}</h2>
<div className="grids">
{b.map((el, ind) => <Card gameEnd={winner? true :false }key={ind} onPlay ={play} players={el} index ={ind}/>)}
</div>
</div>
)
}
export default Grid
grid.css
.grids
{
height: 400px;
width: 400px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.turn-highlight
{
color: aliceblue;
}
Card.css
.card
{
border: 2px solid red;
padding: 1px;
display: flex;
justify-content: center;
align-items: center;
/* //align item : center is used to align the items vertically */
width: 120px;
height: 96px;
border-radius: 15px ;
background-color: var(--yellow);
}
Card.jsx
import Icon from "../Icon/Icon";
import './Card.css'
function Card({gameEnd ,players , onPlay , index})
{ let icon = <Icon/>
// by default the icon will have penicon
if (players == 'x')
{
icon = <Icon name="cross"/>
}
else if (players == '0')
{
icon = <Icon name="circle"/>
}
return(
<div className = 'card' onClick={() => !gameEnd && players =="" && onPlay(index)}>
{/* clasName is reserved should be written in camel case only */}
{icon}
{/* // rendering icon value */}
</div>
)
}
export default Card
Icon.jsx
import { FaPen ,FaRegCircle, FaTimes } from 'react-icons/fa'
// the prompt name should be same as the name given in Card.js
function Icon ({name})
{
if(name == 'circle')
{
return <FaRegCircle/>
}
else if(name == "cross")
{
return < FaTimes/>
}
else
{
return <FaPen/>
}
}
export default Icon
App.jsx
import './App.css'
import Card from './components/Card/Card'
import Grid from './components/Grid/Grid'
function App() {
return (
<>
< Grid numberOfcards={9}/>
</>
)
}
export default App
App.css
:root{
--yellow: #ffc107;
}
body{
background-color: black;
}
CheckWinner.js
// to find the winner
function isWinner(board , symbol)
{
if(board[0] == board[1] && board[1] ==board[2] && board[2] == symbol) return symbol;
if(board[3] == board[4] && board[4] ==board[5] && board[5] == symbol) return symbol;
if(board[6] == board[7] && board[7] ==board[8] && board[8] == symbol) return symbol;
if(board[0] == board[3] && board[6] ==board[3] && board[6] == symbol) return symbol;
if(board[1] == board[4] && board[4] ==board[7] && board[7] == symbol) return symbol;
if(board[2] == board[5] && board[5] ==board[8] && board[8] == symbol) return symbol;
if(board[0] == board[4] && board[8] ==board[4] && board[4] == symbol) return symbol;
if(board[2] == board[4] && board[4] ==board[6] && board[4] == symbol) return symbol;
}
export default isWinner