這個用React做井字遊戲練習是跟著 姚偉揚老師 在HiSKIO 裡 React 16 完全精通 – 從原理到大量實戰應用 的課程練習筆記,課程由淺入深,非常推薦想要學習 React 的人可以訂閱課程。
1. 先定義遊戲的九宮格在state中該如何呈現
0: 空白
1: 圈
-1:叉
state = { grids: [0, 0, 0, 0, 0, 0, 0, 0, 0], player: 1 };
2. 定義 toSymbol(使用switch) 來轉換呈現出來的UI畫面
const toSymbol = elm => { switch(elm) { case 0: return ''; case 1: return 'o'; case -1: defalut: return 'x' } }
將每個格子用map 呈現出來
<div className={style.board}> {grids.map((elm, idx) => ( <div className={style.grid}> <span>{toSymbol(elm)}</span> </div> ))} </div>
3. 建立並定義九宮格樣式,引入Game.js中
import style from “./Game.module.css”;
* { box-sizing: border-box; } .board { width: 240px; height: 240px; display: grid; grid-template-columns: 1fr 1fr 1fr; border: 1px solid #ddd; } .grid { width: 80px; border: 1px solid #ddd; display: flex; justify-content: center; align-items: center; cursor: pointer; } .grid span { font-size: 48px; }
4. 點擊每個格子時,顯示代表的player
這裡的onClick 內要使用arrow function 才能取到當下點擊到的格子(idx)
<div key={idx} className={style.grid} onClick={() => this.handleClick(idx)}> <span>{toSymbol(elm)}</span> </div>
傳入當下點擊到的格子位置(idx) ,並修改state裡的 grids 和 players,player的切換只需在state前加個”負號” 即可 (因為資料定義裡1表示o,-1表示x)
handleClick = idx => { const grids = [...this.state.grids]; grids[idx] = this.state.player; this.setState({ grids, player: -this.state.player }); };
5. 建立清空按鈕
<button className={style.btn} onClick={this.reset}> Clear </button> reset = () => { this.setState({ grids: [0, 0, 0, 0, 0, 0, 0, 0, 0] }); };
6. 判斷如果己點擊的格子不可再點擊
在 handleClick 裡加上 if 判斷式: if (grids[idx] !== 0) return;
handleClick = idx => { const grids = [...this.state.grids]; if (grids[idx] !== 0) return; ...略 };
7. 判斷是有已有連線
建立 lines 的陣列來表示九宮格裡的九個連線,毎個連線亦是一個陣列
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] ];
在每次更新時判斷上一個state的grid和現在的state的grid是否相同,如果不同則更新winner的state(跑 this.getWinner function),確認是否有贏家出現
componentDidUpdate(prevProps, prevState) { if (prevState.grids !== this.state.grids) { this.setState({ winner: this.getWinner() }); } }
建立 getWinner function
getWinner = () => { const { grids } = this.state; for (const line of lines) { const [i, j, k] = line; if (grids[i] === grids[j] && grids[j] === grids[k]) { return grids[i]; } } return 0; };
判斷如有winner出現,則其他格子都不能再點擊 if (this.state.winner !== 0) return
handleClick = idx => { if (this.state.winner !== 0) return ...略
照著以上步驟就完成 React版的井字遊戲囉