react框架學習總結(純乾貨)

首先,我先給出我學習react框架的參考教程,以下內容都是我依據此教程的個人總結。react教程

React與JSX:

function Square(props) {
    return (
        <button className="square" onClick={props.onClick}>
            {props.value}
        </button>
    );
}

React是一個聲明式,高效且靈活的用於構建用戶界面的 JavaScript 庫。使用 React 可以將一些簡短、獨立的代碼片段組合成複雜的 UI 界面,這些代碼片段被稱作“組件”。JSX是JavaScript 的語法擴展,所以其也具有JavaScript 的全部功能,並且建議在React框架中配合使用 JSX,JSX 可以很好地描述 UI 應該呈現出它應有交互的本質形式。
上述給出的一個奇怪的函數代碼就是一個函數組件,它就是採用React框架的JSX語法,其主要體現在兩點表現:一個是代碼裏直接嵌入HTML標籤,另一個是{}裏面可以嵌入表達式。這兩點語法都是原生JavaScript語法所不具備的特性。
注意:jsx語法既可以寫在jsx文件裏也可以直接寫在js文件下
其實簡單看來,React框架主要功能體現在前端UI頁面的渲染,包括性能優化以及操作簡化等等方面。站在mvc框架的角度來看,React操作view層的功能實現。

搭建React環境:
方式一:在網站中添加React
添加一個 DOM 容器到 HTML並添加 相應的Script 標籤:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>react-dom</title>
</head>

<body>
    <div id="like_button_container"></div>
    <!-- 加載 React。-->
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

    <!-- 加載我們的 React 組件。-->
    <script src="like_button.js"></script>
</body>

</html>

創建一個 React 組件:

'use strict';

const e = React.createElement;

class LikeButton extends React.Component {
    constructor(props) {
        super(props);
        this.state = { liked: false };
    }

    render() {
        if (this.state.liked) {
            return 'You liked this.';
        }

        return e(
            'button',
            { onClick: () => this.setState({ liked: true }) },
            'Like'
        );
    }
}
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);

直接運行打開html頁面即可運行。
方式二:Create React App
此方式是通過IDE命令行的方式創建一個本地的React應用項目,也是最佳的創建方式,所以首先得在本地安裝node(Node >= 8.10 和 npm >= 5.6)。
一切準備就緒後,只需一行代碼即可搭建本地React框架:

npx create-react-app my-app

搭建ts版本的react框架(tsx):

npx create-react-app my-app --template typescript

這是搭建好的目錄結構
jsx:
在這裏插入圖片描述

tsx:
在這裏插入圖片描述

項目框架搭建好後在src目錄下添加我們自己的代碼文件。
進入項目根目錄並運行項目:

cd my-app
npm start

jsx:
在這裏插入圖片描述

tsx:
在這裏插入圖片描述
注:有關ts的具體詳細內容我這裏先暫不做講解,如果大家有感覺到突兀可以先參看我給出的ts教程或者參看我下期編寫的ts學習總結。

組件與Props:
組件是React框架中最重要的概念之一,在博客最開始的時候也提到這個詞,現在來詳細的此概念。
組件的概念:組件,從概念上類似於 JavaScript 函數。它接受任意的入參(即 “props”),並返回用於描述頁面展示內容的 React 元素。
在React框架裏有兩種組件:函數組件和類組件
這是函數組件:

function Square(props) {
    return (
        <button className="square" onClick={props.onClick}>
            {props.value}
        </button>
    );
}

這是類組件:

class Board extends React.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>
        );
    }
}

由上面的代碼對比不難發現,函數組件適用於較爲簡單的功能組件,而類組件就適用於較爲複雜的功能組件,類組件將在下一部分state和生命週期中具體講解。
注意:爲了更有效的區分普通函數與函數組件,所有的組件名稱必須以大寫字母開頭。
Props:這是由React內部包裝設置的一個用於傳遞數據的參數,Props最大的特點就是read only,即Props只能被讀取使用但是不能被修改

State和(類組件)生命週期:
什麼是State:Props只能讀取不能修改,顯然肯定滿足不了用戶的需求。爲了滿足React 組件隨用戶操作、網絡響應或者其他變化而動態更改輸出內容的功能,State出現了,它可以用戶自定義。State可以被修改,但是不能直接修改,只能通過setState()函數來修改State裏面的值,這也是State和Props最大的區別。
組件的生命週期:由於函數組件過於簡單而這裏的生命週期是指一些聲明週期方法,所以這裏的生命週期對於類組件而言。
組件的生命週期分爲三個週期:掛載,更新和卸載。
這裏的生命週期方法我不做具體講解,大家可以參看詳細的官方教程。
掛載,當組件實例被創建並插入 DOM 中時,其生命週期調用順序如下:

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

注意:render()方法是類組件中唯一必須實現的方法。因爲最簡單的函數組件裏面的業務邏輯也包含reader()方法的業務邏輯。如果不初始化 state 或不進行方法綁定,則不需要爲 React 組件實現構造函數。
更新,當組件的 props 或 state 發生變化時會觸發更新。組件更新的生命週期調用順序如下:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

注意:此處說的props改變與上述說的props不可修改並不矛盾,上述說的props不可修改是指props在當前組件中不能被修改,而此處說的props改變是指在父組件因爲傳遞參數的內容改變而導致子組件props改變。
卸載,當組件從 DOM 中移除時會調用如下方法:

  • componentWillUnmount()


事件處理:
React元素的事件處理和 DOM 元素的很相似,但是有一點語法上的不同:

  • React 事件的命名採用小駝峯式(camelCase),而不是純小寫。
  • 使用 JSX 語法時你需要傳入一個函數作爲事件處理函數,而不是一個字符串。

React元素的事件處理中this綁定的三種方式:
es5中的bind方法:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

public class fields 語法:

class LoggingButton extends React.Component {
  // 此語法確保 `handleClick` 內的 `this` 已被綁定。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

箭頭函數:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 此語法確保 `handleClick` 內的 `this` 已被綁定。
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}


一些其它的核心概念:
元素渲染: ReactDOM.render()是最頂層的渲染方法,而組件裏面的render方法可以看成它的子成員,ReactDOM.render是唯一一個直接與DOM交互的方法,而其字render方法只改變ReactDOM元素,最終都是由ReactDOM.render來更替UI的DOM元素,所以此方法建議只調用一次。
條件渲染:React 中的條件渲染和 JavaScript 中的一樣,使用 JavaScript 運算符 if 或者條件運算符(包括三目運算符)去創建元素來表現當前的狀態,然後讓 React 根據它們來更新 UI。

render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    // 運算符 if
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
  
  function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      // 條件運算符
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
    // 三目運算符
      {isLoggedIn
        ? <LogoutButton onClick={this.handleLogoutClick} />
        : <LoginButton onClick={this.handleLoginClick} />
      }
    </div>
  );
}

狀態提升:多個組件需要反映相同的變化數據,這時我們將共享狀態提升到最近的共同父組件中去。狀態提升體現的是種代碼設計思想,此思想既能降低代碼的耦合性還能提高代碼的擴展性。
React有十分強大的組合模式。我們推薦使用組合而非繼承來實現組件間的代碼重用。


一個完整的較爲全面覆蓋的simple:
這是官網教程給出的一個井字棋遊戲simple,幾乎涵蓋了我上面列出的所有知識點,甚至還有沒提到的細節知識點。比較React是個很大的框架,我所列出的這些才只是冰山一角。
這個是遊戲實現了四大功能:

  • tic-tac-toe(三連棋)遊戲的所有功能
  • 能夠判定玩家何時獲勝
  • 能夠記錄遊戲進程
  • 允許玩家查看遊戲的歷史記錄,也可以查看任意一個歷史版本的遊戲棋盤狀態

css代碼:

body {
    font: 14px "Century Gothic", Futura, sans-serif;
    margin: 20px;
  }
  
  ol, ul {
    padding-left: 30px;
  }
  
  .board-row:after {
    clear: both;
    content: "";
    display: table;
  }
  
  .status {
    margin-bottom: 10px;
  }
  
  .square {
    background: #fff;
    border: 1px solid #999;
    float: left;
    font-size: 24px;
    font-weight: bold;
    line-height: 34px;
    height: 34px;
    margin-right: -1px;
    margin-top: -1px;
    padding: 0;
    text-align: center;
    width: 34px;
  }
  
  .square:focus {
    outline: none;
  }
  
  .kbd-navigation .square:focus {
    background: #ddd;
  }
  
  .game {
    display: flex;
    flex-direction: row;
  }
  
  .game-info {
    margin-left: 20px;
  }
  

js(jsx)代碼:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
function Square(props) {
    return (
        <button className="square" onClick={props.onClick}>
            {props.value}
        </button>
    );
}

class Board extends React.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>
        );
    }
}

class Game extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            history: [
                {
                    squares: Array(9).fill(null)
                }
            ],
            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 (calculateWinner(squares) || squares[i]) {
            return;
        }
        squares[i] = this.state.xIsNext ? "X" : "O";
        this.setState({
            history: history.concat([
                {
                    squares: squares
                }
            ]),
            stepNumber: history.length,
            xIsNext: !this.state.xIsNext
        });
    }

    jumpTo(step) {
        this.setState({
            stepNumber: step,
            xIsNext: (step % 2) === 0
        });
    }

    render() {
        const history = this.state.history;
        const current = history[this.state.stepNumber];
        const winner = calculateWinner(current.squares);

        const moves = history.map((step, move) => {
            const desc = move ?
                'Go to move #' + move :
                'Go to game start';
            return (
                <li key={move}>
                    <button onClick={() => this.jumpTo(move)}>{desc}</button>
                </li>
            );
        });

        let status;
        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>
        );
    }
}
// ========================================

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

function 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];
        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
            return squares[a];
        }
    }
    return null;
}

最後,由於我也只是個React初學者,此篇博客裏面含有很多我自己的理解成分,難免會有錯誤理解,如果有發現錯誤的朋友歡迎評論區指出。路漫漫其修遠,此篇博客的內容才只是React框架的冰山一角,希望能對大家有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章