(lt.50) Master React State Hook, Keys, and Props with a Tic-Tac-Toe Project Tutorial

(lt.50) Master React State Hook, Keys, and Props with a Tic-Tac-Toe Project Tutorial

·

6 min read

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

Did you find this article valuable?

Support himanshu by becoming a sponsor. Any amount is appreciated!