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学习总结。
ts官方教程

组件与Props:
组件是React框架中最重要的概念之一,在博客最开始的时候也提到这个词,现在来详细的此概念。
组件的概念:组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
在React框架里有两种组件:函数组件和类组件
这是函数组件:

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

这是类组件:

扫描二维码关注公众号,回复: 11449223 查看本文章
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框架的冰山一角,希望能对大家有所帮助。

猜你喜欢

转载自blog.csdn.net/asd0356/article/details/105867616