首先
我覺得React的文件對我這個急性子的人來說,有點跳耀,所以我想整理一下先後順序
1. Create a New React App
https://reactjs.org/docs/create-a-new-react-app.html
用Vue cli用到離不開的我,當然也希望新的框架有個手腳架
於是就無腦下指令
npx create-react-app my-app
cd my-app
npm start
2. 編輯器VS code的ES7 React/Redux/GraphQL/React-Native snippets
https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets
快捷鍵用下去才有打扣的動力
3. 觀察一下src/App.js
import React from 'react';
輸入imr可跳出
import logo from './logo.svg';
輸入imp可跳出
import './App.css';
輸入imn可跳出
//輸入rce可跳出
import React, { Component } from 'react'
export class App extends Component {
render() {
return (
<div>
</div>
)
}
}
export default App
4. 創建其他component
//src/App.js
import React from 'react';
import Board from './Board'
function App() {
return (
<div className="App">
<Board></Board>
</div>
);
}
export default App;
//src/Board.js
import React, { Component } from 'react'
import Square from './Square'
export class Board extends Component {
renderSquare(i){
return <Square value={i} />
}
//輸入ren可以叫出模板
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>
)
}
}
export default Board
//src/Square.js
import React, { Component } from 'react'
export class Square extends Component {
render() {
return (
<button className="square">
{ this.props.value }
</button>
)
}
}
export default Square
呈現結果
5. 設定component自己的state, 此例中,按每個按鈕都可以把按鈕的值變成X
//src/Square.js
import React, { Component } from 'react'
export class Square extends Component {
//輸入rconst可跳出
constructor(props) {
super(props)
this.state = {
value: 0
}
}
render() {
return (
<button
className="square"
onClick={ ()=> this.setState({ value: 'X' }) }
>
{ this.state.value }
</button>
)
}
}
export default Square
6. 把事件由下往上傳,同第五點之效果,code中的slice是為了immutability特性
// src/Board.js
import React, { Component } from 'react'
import Square from './Square'
export class Board extends Component {
constructor(props) {
super(props)
this.state = {
squares: Array(9).fill(0)
}
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({ squares })
}
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>
)
}
}
export default Board
// src/Square.js
import React, { Component } from 'react'
export class Square extends Component {
render() {
return (
<button
className="square"
onClick={ ()=> this.props.onClick() }
>
{ this.props.value }
</button>
)
}
}
export default Square
7. 按了一下就換一個玩家// src/Board.js
import React, { Component } from 'react'
import Square from './Square'
export class Board extends Component {
constructor(props) {
super(props)
this.state = {
squares: Array(9).fill(0),
xIsNext: true
}
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares,
xIsNext: !this.state.xIsNext
})
}
renderSquare(i){
return (
<Square
value={this.state.squares[i]}
onClick={ ()=> this.handleClick(i) }
/>
)
}
render() {
const 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>
</div>
)
}
}
export default Board
8. 決定Winner是誰// src/Board.js
import React, { Component } from 'react'
import Square from './Square'
export class Board extends Component {
constructor(props) {
super(props)
this.state = {
squares: Array(9).fill(0),
xIsNext: true
}
}
calculateWinner(squares) {
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];
//第一格不是null
//第一格和第二格一樣(都是O或X)
//第二格和第三格一樣(都是O或X)
if(squares[a] && squares[a] === squares[b] && squares[a] === squares[c] ){
return squares[a]; //O或X
}
}
return null;
}
handleClick(i) {
const squares = this.state.squares.slice();
if(this.calculateWinner(squares) || squares[i]){
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares,
xIsNext: !this.state.xIsNext
})
}
renderSquare(i){
return (
<Square
value={this.state.squares[i]}
onClick={ ()=> this.handleClick(i) }
/>
)
}
render() {
let status;
const winner = this.calculateWinner(this.state.squares);
if(winner){
status = `Winner: ${winner}`;
}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>
</div>
)
}
}
export default Board
9. 增加歷史記錄與跳轉功能
多加一個game component
import React, { Component } from 'react'
import functions from './functions';
import Board from './Board';
export class Game extends Component {
constructor(props) {
super(props)
this.state = {
history: [{
squares: Array(9).fill(0)
}],
stepNumber: 0,
xIsNext: true
}
}
handleClick(i) {
const history = this.state.history.slice(0, this.state.stepNumber + 1);
const current = history[history.length - 1];
const squares = current.squares.slice();
if(functions.calculateWinner(squares) || squares[i]){
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares
}]),
stepNumber: history.length,
xIsNext: !this.state.xIsNext
})
}
jumpTo(step) {
this.setState({
stepNumber: step,
xIsNext: (step % 2 ) === 0 // 2的倍數的step都是X
})
}
render() {
let status;
const history = this.state.history;
const current = history[this.state.stepNumber];
const winner = functions.calculateWinner(current.squares);
const moves = history.map((step, move) => {
const desc = move ? `Go to move # ${ move }` : `Go to game start`;
return (
<li>
<button onClick={ ()=> this.jumpTo(move) }>{ desc }</button>
</li>
)
})
if(winner){
status = `Winner: ${winner}`;
}else{
status = `Next player: ${ this.state.xIsNext ? 'X' : 'O' }`;
}
return (
<div className="game">
<div className="game-board">
<Board
squares={ current.squares }
onClick={ i => this.handleClick(i) }
/>
</div>
<div className="game-info">
<div>{ status }</div>
<ol>{ moves }</ol>
</div>
</div>
)
}
}
export default Game
修改Board componenent
import React, { Component } from 'react'
import Square from './Square'
export class Board extends Component {
renderSquare(i){
return (
<Square
value={this.props.squares[i]}
onClick={ ()=> this.props.onClick(i) }
/>
)
}
render() {
return (
<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>
)
}
}
export default Board
Github網址
沒有留言:
張貼留言