Skip to main content

React.js概览

React是什么

React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。

React 中拥有多种不同类型的组件,我们先从 React.Component 的子类开始介绍:

class ShoppingList extends React.Component {
render() {
return (
//以下是一个react元素
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}

// 用法示例: <ShoppingList name="Mark" />

在上面的代码中,使用了组件的形式来告诉React我们希望在屏幕上呈现的内容。正是因为函数式声明,使得在数据发生变化时React能够高效地重新渲染组件。

我们首先定义了一个叫ShoppingList组件类,每一个组件可以接受一些参数,这些参数被称为props,上面的name="Mark"就是将参数传入组件的过程。然后再通过render渲染到页面。

JSX语法

由React扩展的Js语法,JSX 可以让你更轻松地书写这些函数式声明结构。

上面的这些代码等同于:

return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);

在 JSX 中你可以任意使用 JavaScript 表达式,只需要用一个大括号把表达式括起来。每一个 React 元素事实上都是一个 JavaScript 对象,你可以在你的程序中把它当保存在变量中或者作为参数传递。

前文中的 ShoppingList 组件只会渲染一些内置的 DOM 组件,如<div /><li />等。但是你也可以组合和渲染自定义的 React 组件。例如,你可以通过 <ShoppingList /> 来表示整个购物清单组件。每个组件都是封装好的,并且可以单独运行,这样你就可以通过组合简单的组件来构建复杂的 UI 界面。

阅读初始代码

在前面我们初始化的源代码中,打开 src/index.js ,这些初始代码是我们要开发的小游戏的基础代码。在上面已经提供了 CSS 样式,这样你只需要关注使用 React 来开发这个井字棋了。

通过阅读代码可以看到三个组件:

Square-棋盘格

src/index.js
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}

我们可以看到,Square组件返回了一个类名叫 squarebutton 按钮。React 将这个类名为 square 组件封装成了一个组件,方便后面调用。

在 css 代码中,它有这样的样式:

.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;
}

Board-棋盘

在这个命名为 Board 的函数中利用上面的 Square 的组件创建了一个九宫格,这个九宫格由三行组成,每行由三个棋盘格组成。

class Board extends React.Component {
renderSquare(i) {
return <Square />;
}

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>
);
}
}

Game-游戏主体

在这个函数中,利用上面的棋盘封装了一个游戏界面。

class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}

通过 Props 传递数据

每个定义的组件之间可以通过 Props 传递参数。我们尝试将数据从 Board 组件传递到 Square 组件中。
Board 组件的 renderSquare 方法中,我们将代码改写成下面这样,传递一个名为 valuepropSquare 当中:

class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
···
}

修改 Square 组件中的 render 方法,把 {/*TODO*/} 替换为 {this.props.value} ,以显示上文中传入的值:

class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value}
</button>
);
}
}

修改前:

1

修改后,每个格子中都会存在一个数字:

2

我们刚刚成功地把一个 prop 从父组件 Board “传递”给了子组件 Square 。在 React 应用中,数据通过 props 的传递,从父组件流向子组件。也就是说,我们成功 Board 中传递的参数值(0~8)给了子组件进行处理,并显示出来。

给组件添加交互功能

接下来我们试着让棋盘的每一个格子在点击之后能落下一颗 X 作为棋子。 首先,我们把 Square 组件中 render() 方法的返回值中的 button 标签修改为如下内容:

class Square extends React.Component {
render() {
return (
<button className="square" onClick={function () { alert('click') }}>
{this.props.value}
</button>
);
}
}

如果此刻点击某个格子,浏览器会弹出提示框。触发事件 onClick ,显示出提示:“click”。在这里 alert 是弹出事件,括号里面的是弹出参数。

JavaScript 箭头函数

为了少输入代码,同时为了避免 this 造成的困扰,我们在这里使用箭头函数 来进行事件处理,如下所示:

onClick={() => alert('click')}

此处使用了 onClick={() => alert('click')} 的方式向 onClick 这个 prop 传入一个函数。 React 将在单击时调用此函数。但很多人经常忘记编写 () =>,而写成了 onClick={alert('click')},这种常见的错误会导致每次这个组件渲染的时候都会触发弹出框。

接下来,我们希望 Square 组件可以“记住”它被点击过,然后用 “X” 来填充对应的方格。我们用 state 来实现所谓“记忆”的功能。

可以通过在 React 组件的构造函数中设置 this.state 来初始化 state。this.state 应该被视为一个组件的私有属性。我们在 this.state 中存储当前每个方格(Square)的值,并且在每次方格被点击的时候改变这个值

首先,我们向这个 class 中添加一个构造函数,用来初始化 state:

React 构造函数

constructor 函数时组件最先执行的函数。

class childen extends react.Component{
constructor(props){
super(props);
this.state={
attr1:"",
}
}
}

spuer(): 注意在定义组件的时候可以没用constructor方法,一旦定义,就必须使用spuer方法,这不是react规定的而是es6要求,具体原因如下:
3

首先,我们向这个 class 中添加一个构造函数,用来初始化 state:

class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
// 用于记忆状态
value: null,
}
}
render() {
return (
<button className="square" onClick={() => alert("Click!")}>
{this.props.value}
</button>
);
}
}

现在,我们来修改一下 Square 组件的 render 方法,这样,每当方格被点击的时候,就可以显示当前 state 的值了:

  • <button> 标签中,把 this.props.value 替换为 this.state.value
  • onClick={...} 事件监听函数替换为 onClick={() => this.setState({value: 'X'})}
  • 为了更好的可读性,将 classNameonClickprop 分两行书写。

修改之后,Square 组件中 render 方法的返回值中的 <button> 标签就变成了下面这样:

class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
// 用于记忆状态
value: null,
}
}
render() {
return (
<button
className="square"
onClick={() => this.setState({ value: 'x' })}>
{this.state.value}
</button>
);
}
}

每次在组件中调用 setState 时,React 都会自动更新其子组件。

3