iT邦幫忙

1

React 學習筆記_14(React 圈圈叉叉練習 - 1)

前言

主要練習React官網中的題目,使用React達成做出圈圈叉叉的小遊戲,練習項目為

  • 利用props傳遞資料
  • 建立互動式Component
  • 提升State

Step1 建立React Components

主要建立三個Components : Game,Board,Square
Components Tree :
https://ithelp.ithome.com.tw/upload/images/20200403/20124767Lecg5pU7Hx.png

Game :

import React from "react"
import Board from "./Board"

class Game extends React.Component
{
    render()
    {
        return(
           <Board />
        )
    }
}

ReactDOM.render(<Game />,document.getElementById("root"));

Board :

import React from "react"
import Square from "./Square"

class Board extends React.Component
{
    render()
    {
        return(
            <Square />
        )
    }
}
export default Board;

Square :

import React from "react"

class Square extends React.Component
{
    render()
    {
        return(
            <div> Square Component </div>
        )
    }
}
export default Square;

Step2 利用props傳遞資料

在Board中利用props將數據傳遞給Square後將他選染出來

Board :

class Board extends React.Component
{
    renderSquare(i) {
        return <Square value={i} />;
      }

    render()
    {
        const status = 'Next player: X';

        return(
            <div>
            <div className="status">{status}</div>
            <div className="board-row">
                {this.renderSquare(0)} //將數字裡用props傳遞給Square
                {this.renderSquare(1)}
                {this.renderSquare(2)}
            </div>
            <div className="board-row">
                {this.renderSquare(3)}
                {this.renderSquare(4)}
                {this.renderSquare(5)}
            </div>
            <div className="board-row">
                {this.renderSquare(6)}
                {this.renderSquare(7)}
                {this.renderSquare(8)}
            </div>
        </div>
        )
    }
}

Square :

class Square extends React.Component
{
    render()
    {
        return(
            <button className="square">
                {this.props.value} //接收父層(Board)所傳遞的數字
            </button>
        )
    }
}

結果 :
https://ithelp.ithome.com.tw/upload/images/20200403/20124767BVjkQ3Ag0x.png

Step3 建立互動Component

當點擊 Square component 時,能在方格中填入一個 X。

Square :
1.在Square中建立一個state以初始化Square Vaule中的值
2.建立一個function,當被點擊時觸發改變state中的值("" -> "X")

class Square extends React.Component
{
    //Step1 : 建立constructor以初始化state中的Value
    constructor(props)
    {
        super(props);
        this.state = {
            value:""
        }
    }

    //Step2 : 建立一個function當點擊時觸發
    handleClick = (e) => {
        this.setState({
            value : "X" //利用setState改變State中的值
        });
    }

    render()
    {
        return(
            <button className="square" onClick={this.handleClick}> //點擊時觸發
                {this.state.value}
            </button>
        )
    }
}

Step3 : 提升State

為了一次性的紀錄這九個方格中的值,所以需要將state提升到父層(Board)。

Board :
1.將state提升到父層(Board)
2.在父層建立當Square被點擊時觸發的function
3.將State的Value與handleClick function藉由props傳遞給Square

class Board extends React.Component
{
    //Step1 : 將state提升到Board
    constructor(props)
    {
        super(props);
        this.state = {
            squares : Array(9).fill("") //建立大小為9的陣列並填入""
        };
    }

    //Step2 :建立當Square被點擊時觸發的function
    handleClick = (i) => {
        const squares = this.state.squares.slice();
        squares[i] = 'X';
        this.setState({squares: squares});
    }
    
    
    renderSquare(i) {
        //Step3 :利用props傳遞給子層(Square)
        return <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)}/>;
      }

    render()
    {
        const status = 'Next player: X';

        return(
            <div>
            <div className="status">{status}</div>
            <div className="board-row">
                {this.renderSquare(0)}
                {this.renderSquare(1)}
                {this.renderSquare(2)}
            </div>
            <div className="board-row">
                {this.renderSquare(3)}
                {this.renderSquare(4)}
                {this.renderSquare(5)}
            </div>
            <div className="board-row">
                {this.renderSquare(6)}
                {this.renderSquare(7)}
                {this.renderSquare(8)}
            </div>
        </div>
        )
    }
}

Square :
1.移除自身state
2.將this.state更改為this.props(參數由父層傳遞)

class Square extends React.Component
{
    //Step1 : 移除自身state

    render()
    {
        return(
            //Step2 : 將this.state更改為this.props(參數由父層傳遞)
            <button className="square" onClick={() => this.props.onClick()}>
                {this.props.value}
            </button>
        )
    }
}

結果 :
https://ithelp.ithome.com.tw/upload/images/20200403/20124767WQWvcbtuUz.png

Step4 : 加入輪流功能

會將第一步的預設值設定為"X",並設定一個boolean來判斷由"X"改為"O"以達到輪流的功能。

Board :
1.新增一個boolean xIsNext 來判斷符號的輪流
2.在handleClick function中建立判斷式以判斷現在的符號的狀況(xIsNext true or false)
3.反轉xIsNext狀態

class Board extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state = {
            squares : Array(9).fill(""),
            xIsNext : true //Step1 :新增一個boolean xIsNext
        };
    }

    handleClick = (i) => {
        const squares = this.state.squares.slice();
        squares[i] = this.state.xIsNext?"X":"O";  //Step2 :判斷現在的符號的狀況
        this.setState({
            squares : squares,
            xIsNext : !this.state.xIsNext //Step3 :反轉xIsNext狀態
        });
    }

    renderSquare(i) {
        return <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)}/>;
    }

    render()
    {
        const status = 'Next player: X';

        return(
            <div>
            <div className="status">{status}</div>
            <div className="board-row">
                {this.renderSquare(0)}
                {this.renderSquare(1)}
                {this.renderSquare(2)}
            </div>
            <div className="board-row">
                {this.renderSquare(3)}
                {this.renderSquare(4)}
                {this.renderSquare(5)}
            </div>
            <div className="board-row">
                {this.renderSquare(6)}
                {this.renderSquare(7)}
                {this.renderSquare(8)}
            </div>
        </div>
        )
    }
}

結果 :
https://ithelp.ithome.com.tw/upload/images/20200403/20124767GGdBSph4Sz.png

Step 5 : 決定勝負

建立一個function已檢測哪一方勝利,並在建立一個funciton再分出勝負後清除表格中的符號。

function calculateWinner :

  1. 建立一個九個 square 的 array,記錄各個勝利條件
  2. 檢測輸入的參數是否有達成獲勝條件(若達成條件則輸出獲勝的符號)
export const calculateWinner = (squares) => {

    //Step 1:建立一個九個勝利條件的Array
    const lines = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6],
      ];
      for (let i = 0; i < lines.length; i++) 
      {
        const [a, b, c] = lines[i];
        //Step 2:檢測輸入的參數是否有達成獲勝條件
        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) 
        {
          return squares[a]; //輸出獲勝的符號
        }
      }
      return null;
}

Board :
1.建立一個參數(Winner)用來存取function calculateWinner計算的結果
2.利用Winner來判斷是否達成獲勝條件
3.新增一個按鈕用來重新開始
4.新增當重新開始按鈕被點擊後觸發的function

import {calculateWinner} from "./calculateWinner" //include function

class Board extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state = {
            squares : Array(9).fill(""),
            xIsNext : true
        };
    }

    handleClick = (i) => {
        const squares = this.state.squares.slice();
        squares[i] = this.state.xIsNext?"X":"O";
        this.setState({
            squares : squares,
            xIsNext : !this.state.xIsNext
        });
    }

    renderSquare(i) {
        return <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)}/>;
    }

    //Step 4:當重新開始按鈕被點擊後觸發的function
    Reset = () => {
        const emply = this.state.squares.fill("");
        this.setState({
            squares : emply,
            xIsNext : true
        });
    }

    render()
    {
        //Step 1:建立一個參數(Winner)用來存取function calculateWinner計算的結果
        const Winner = calculateWinner(this.state.squares);
        let status;

        //Step 2:判斷是否達成獲勝條件
        if(Winner)
        {
            status = "Winner :" + Winner;
            alert(status);
        }
        else
        {
            status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
        }

        return(
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
                <dic>
                    //Step 3:新增一個按鈕用來重新開始
                    <button onClick={this.Reset}>ReStart</button> 
                </dic>
            </div>
        )
    }
}

結果:
https://ithelp.ithome.com.tw/upload/images/20200404/201247675bA8cAKCio.png

參考資料 :
React學習指南


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言