React是一个用于构建用户界面的声明性,高效且灵活的JavaScript库。它允许您从称为“组件”的小而孤立的代码片段中组合复杂的UI。
React有几种不同的组件,但我们将从React.Component
子类开始:
class ShoppingList extends React.Component { render() { return ( <div className="shopping-list"> <h1>Shopping List for {this.props.name}</h1> <ul> <li>Instagram</li> <li>WhatsApp</li> <li>Oculus</li> </ul> </div> ); } } // Example usage: <ShoppingList name="Mark" />
我们很快就会得到有趣的类似XML的标签。我们使用组件告诉React我们想要在屏幕上看到什么。当我们的数据发生变化时,React将有效地更新和重新渲染我们的组件。
这里,ShoppingList是一个React组件类,或React组件类型。组件接受称为props
(“属性”的缩写)的参数,并返回要通过该render
方法显示的视图层次结构。
该render
方法返回您想要在屏幕上看到的内容的描述。React接受描述并显示结果。特别是,render
返回一个React元素,它是渲染内容的轻量级描述。大多数React开发人员使用称为“JSX”的特殊语法,这使得这些结构更容易编写。该<div />
语法在构建时被转化React.createElement('div')
。上面的例子相当于:
return React.createElement('div', {className: 'shopping-list'}, React.createElement('h1', /* ... h1 children ... */), React.createElement('ul', /* ... ul children ... */) );
通过道具传递数据
为了让我们的脚湿透,让我们尝试将一些数据从我们的Board组件传递到Square组件。
在Board的renderSquare
方法中,更改代码以传递调用value
Square 的道具:
class Board extends React.Component { renderSquare(i) { return <Square value={i} />; }
render
通过替换{/* TODO */}
为{this.props.value}
:更改Square的方法来显示该值:
class Square extends React.Component { render() { return ( <button className="square"> {this.props.value} </button> ); } }
class Square extends React.Component { render() { return ( <button className="square" onClick={() => alert('click')}> {this.props.value} </button> ); } }
请注意onClick={() => alert('click')}
,我们将函数作为onClick
prop 传递。它只在点击后触发。忘记() =>
和写入onClick={alert('click')}
是一个常见的错误,每次组件重新渲染时都会触发警报。
下一步,我们希望Square组件“记住”它被点击,并用“X”标记填充它。为了“记住”事物,组件使用状态。
React组件可以通过this.state
在其构造函数中设置来具有状态。this.state
应被视为对其定义的React组件的私有。让我们存储Square的当前值this.state
,并在单击Square时更改它。
首先,我们将在类中添加一个构造函数来初始化状态:
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> ); } }
在JavaScript类中,您需要super
在定义子类的构造函数时始终调用。所有具有a的React组件类都constructor
应该通过super(props)
调用启动它。
现在我们将更改Square的render
方法,以便在单击时显示当前状态的值:
- 更换
this.props.value
用this.state.value
的内部<button>
标签。 () => alert()
用() => this.setState({value: 'X'})
。替换事件处理程序。- 将
className
和onClick
道具放在不同的线上以提高可读性。
在这些更改之后,<button>
Square render
方法返回的标记如下所示:
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> ); } }
通过使用Square 方法中this.setState
的onClick
处理程序调用render
,我们告诉React在<button>
单击它时重新呈现该Square 。更新后,Square this.state.value
将会是'X'
,所以我们将X
在游戏板上看到。如果你点击任何Square,X
就会显示出来。
当您调用setState
组件时,React也会自动更新其中的子组件。
class Board extends React.Component { constructor(props) { super(props); this.state = { squares: Array(9).fill(null), }; } renderSquare(i) { return <Square value={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> ); } }
为了便于阅读,我们将返回的元素拆分为多行,并添加了括号,以便JavaScript不会在return
我们的代码之后插入分号。
现在我们传递了从Board到Square的两个道具:value
和onClick
。该onClick
道具是点击后Square可以调用一个函数。我们将对Square进行以下更改:
- 更换
this.state.value
用this.props.value
在Square的render
方法 - 更换
this.setState()
用this.props.onClick()
在Square的render
方法 - 删除
constructor
Square,因为Square不再跟踪游戏的状态
完成这些更改后,Square组件如下所示:
class Square extends React.Component { render() { return ( <button className="square" onClick={() => this.props.onClick()} > {this.props.value} </button> ); } }
单击Square时,将onClick
调用Board提供的功能。以下是对如何实现这一目标的回顾:
onClick
内置DOM<button>
组件的prop 告诉React设置一个click事件监听器。- 单击该按钮时,React将调用
onClick
Squarerender()
方法中定义的事件处理程序。 - 此事件处理程序调用
this.props.onClick()
。Square的onClick
支柱由董事会指定。 - 自从董事会转移
onClick={() => this.handleClick(i)}
到Square后,Squarethis.handleClick(i)
点击时调用。 - 我们尚未定义该
handleClick()
方法,因此我们的代码崩溃了。
注意
DOM <button>
元素的onClick
属性对React具有特殊含义,因为它是一个内置组件。对于像Square这样的自定义组件,命名取决于您。我们可以用不同onClick
的handleClick
方式命名Square的prop或Board的方法。但是,在React中,使用on[Event]
道具名称来表示事件和handle[Event]
处理事件的方法是一种惯例。
当我们尝试点击Square时,我们应该会收到错误,因为我们还没有定义handleClick
。我们现在将添加handleClick
到Board类:
class Board extends React.Component { constructor(props) { super(props); this.state = { squares: Array(9).fill(null), }; } handleClick(i) { const squares = this.state.squares.slice(); squares[i] = 'X'; this.setState({squares: 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>