2019年9月23日 星期一

[React] 從Vue轉到React到底難不難,來試試


首先
我覺得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網址


沒有留言:

張貼留言