首先,我先给出我学习react框架的参考教程,以下内容都是我依据此教程的个人总结。react教程
React与JSX:
function Square(props) {
return (
);
}
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 标签:
react-dom
创建一个 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
项目框架搭建好后在src目录下添加我们自己的代码文件。
进入项目根目录并运行项目:
cd my-app
npm start
tsx:
注:有关ts的具体详细内容我这里先暂不做讲解,如果大家有感觉到突兀可以先参看我给出的ts教程或者参看我下期编写的ts学习总结。
ts官方教程
组件与Props:
组件是React框架中最重要的概念之一,在博客最开始的时候也提到这个词,现在来详细的此概念。
组件的概念:组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
在React框架里有两种组件:函数组件和类组件
这是函数组件:
function Square(props) {
return (
);
}
这是类组件:
class Board extends React.Component {
renderSquare(i) {
return (
this.props.onClick(i)}
/>
);
}
render() {
return (
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
);
}
}
由上面的代码对比不难发现,函数组件适用于较为简单的功能组件,而类组件就适用于较为复杂的功能组件,类组件将在下一部分state和生命周期中具体讲解。
注意:为了更有效的区分普通函数与函数组件,所有的组件名称必须以大写字母开头。
Props:这是由React内部包装设置的一个用于传递数据的参数,Props最大的特点就是read only,即Props只能被读取使用但是不能被修改。
State和(类组件)生命周期:
什么是State:Props只能读取不能修改,显然肯定满足不了用户的需求。为了满足React 组件随用户操作、网络响应或者其他变化而动态更改输出内容的功能,State出现了,它可以用户自定义。State可以被修改,但是不能直接修改,只能通过setState()函数来修改State里面的值,这也是State和Props最大的区别。
组件的生命周期:由于函数组件过于简单而这里的生命周期是指一些声明周期方法,所以这里的生命周期对于类组件而言。
组件的生命周期分为三个周期:挂载,更新和卸载。
这里的生命周期方法我不做具体讲解,大家可以参看详细的官方教程。
挂载,当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
注意:render()方法是类组件中唯一必须实现的方法。因为最简单的函数组件里面的业务逻辑也包含reader()方法的业务逻辑。如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
更新,当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
注意:此处说的props改变与上述说的props不可修改并不矛盾,上述说的props不可修改是指props在当前组件中不能被修改,而此处说的props改变是指在父组件因为传递参数的内容改变而导致子组件props改变。
卸载,当组件从 DOM 中移除时会调用如下方法:
事件处理:
React元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
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 (
);
}
}
public class fields 语法:
class LoggingButton extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
);
}
}
箭头函数:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
);
}
}
一些其它的核心概念:
元素渲染: 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 = ;
} else {
button = ;
}
return (
{button}
);
}
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
Hello!
// 条件运算符
{unreadMessages.length > 0 &&
You have {unreadMessages.length} unread messages.
}
);
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
// 三目运算符
{isLoggedIn
?
:
}
);
}
状态提升:多个组件需要反映相同的变化数据,这时我们将共享状态提升到最近的共同父组件中去。状态提升体现的是种代码设计思想,此思想既能降低代码的耦合性还能提高代码的扩展性。
React有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
一个完整的较为全面覆盖的simple:
这是官网教程给出的一个井字棋游戏simple,几乎涵盖了我上面列出的所有知识点,甚至还有没提到的细节知识点。比较React是个很大的框架,我所列出的这些才只是冰山一角。
这个是游戏实现了四大功能:
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 (
);
}
class Board extends React.Component {
renderSquare(i) {
return (
this.props.onClick(i)}
/>
);
}
render() {
return (
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
);
}
}
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 (
);
});
let status;
if (winner) {
status = "Winner: " + winner;
} else {
status = "Next player: " + (this.state.xIsNext ? "X" : "O");
}
return (
this.handleClick(i)}
/>
{status}
{moves}
);
}
}
// ========================================
ReactDOM.render( , 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框架的冰山一角,希望能对大家有所帮助。