一、事件处理
1、事件处理
React 元素的事件处理和 DOM 元素的相似,但是有一点语法上的不同,我们来看一个简单的例子
<!DOCTYPE html> <html> <head> <title>Demo</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone"></script> </head> <body> <div id="app"></div> <script type="text/babel"> class Counter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; // 为事件处理函数绑定组件实例 // 绑定组件实例目的是为了能在事件处理函数中使用 this this.handleClick = this.handleClick.bind(this); } handleClick(e) { // 这里传入的 `e` 是一个合成事件 // 拥有与浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault() this.setState((state) => ({ counter: state.counter + 1 })); } render() { return ( <div> <p>{ this.state.counter }</p><br/> {/*事件命名采用小驼峰式,而不是纯小写*/} {/*传入一个函数作为事件处理函数,而不是一个字符串*/} <button onClick={ this.handleClick }>加 1</button> </div> ); } } ReactDOM.render( <Counter />, document.getElementById('app') ); </script> </body> </html>
2、this 绑定
在上面的例子中,我们在 constructor()
中为事件处理函数绑定 this
请注意,在 JavaScript 中,class
的方法默认是不会绑定 this
的,也就是说
假如我们没有绑定 this.handleClick
并将其传入 onClick
,那么当调用这个函数时,this
的值将为 undefined
如果希望在事件处理函数中使用 this
,那么为事件处理函数绑定 this
是必须的,方法有三种:
(1)在构造函数中使用 bind
class PrintThis extends React.Component { // 在构造函数中使用 `bind` constructor(props) { super(props) this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this) } render() { return ( <button onClick={ this.handleClick }>Print This</button> ); } }
(2)在事件处理函数中使用 public class fields 语法
class PrintThis extends React.Component { constructor(props) { super(props) } // 在事件处理函数中使用 `public class fields 语法` handleClick = () => { console.log(this) } render() { return ( <button onClick={ this.handleClick }>Print This</button> ); } }
(3)在回调函数中使用 箭头函数
class PrintThis extends React.Component { constructor(props) { super(props) } handleClick = () => { console.log(this) } render() { return ( <div> {/*在回调函数中使用 `箭头函数`*/} <button onClick={ (e) => this.handleClick(e) }>Print This</button> </div> ); } }
3、传递参数
有的时候,我们还需要给事件传递额外的参数
class SayHello extends React.Component { // 事件处理函数接收的参数必须在合成事件 `e` 之前 sayHelloTo(somebody, e) { alert('Hello ' + somebody); } render() { return ( <div> {/* 既可以使用 箭头函数 */} <button onClick={ (e) => this.sayHelloTo('Alice', e) }>Say Hello To Alice</button> {/* 也可以使用 Function.prototype.bind */} <button onClick={ this.sayHelloTo.bind(this, 'Bob') }>Say Hello To Bob</button> </div> ); } }
二、表单元素
1、受控组件
在 HTML 中,表单元素通常自己维护状态,并且根据用户输入事件进行更新
但是在 React 中,可变状态通常保存在组件的 state
属性中,并且只能通过 setState()
方法进行更新
如果我们希望组件的 state 还是唯一数据源,同时还控制着用户输入事件,这样的组件我们称之为 受控组件
class InfoForm extends React.Component { constructor(props) { super(props) this.state = { name: '', phone: '' } // 提供默认值 this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } // 为用户事件(state 发生改变)定义处理函数 handleChange(event) { // console.log(event.target) const target = event.target // 如果需要处理多个 input 元素,那么可以根据 `target.name` 执行不同的操作 if (target.name === 'userName') { this.setState({ name: target.value }) } else { // target.name === 'userPhone' this.setState({ phone: target.value }) } } handleSubmit(event) { alert('您的名字是 ' + this.state.name + ';' + '您的手机是 ' + this.state.phone) event.preventDefault() } render() { return ( // onSubmit 属性为提交事件指定处理函数 <form onSubmit={ this.handleSubmit }> {/* type 属性指定 input 元素的类型 */} {/* name 属性指定每个 input 元素的唯一标识符 */} {/* value 属性指向 state 数据,使得 state 成为唯一的数据源 */} {/* onChange 属性为 value 改变指定处理函数 */} 您的姓名:<input type="text" name="userName" value={ this.state.name } onChange={ this.handleChange } /><br /><br /> 您的手机:<input type="text" name="userPhone" value={ this.state.phone } onChange={ this.handleChange } /><br /><br /> <input type="submit" value="提交" /> </form> ) } }
2、非受控组件
除了通过受控组件让 React 组件管理表单数据,还能使用非受控组件让 DOM 节点处理表单数据
编写非受控组件,我们无需为每个状态更新都写一个处理函数,只需用 ref
从 DOM 节点中获取表单数据
class InfoForm extends React.Component { constructor(props) { super(props) this.handleSubmit = this.handleSubmit.bind(this) // 使用 `React.createRef()` 创建 ref this.nameInput = React.createRef() this.phoneInput = React.createRef() } handleSubmit(event) { alert('您的名字是 ' + this.nameInput.current.value + ';' + '您的手机是 ' + this.phoneInput.current.value) event.preventDefault() } render() { return ( // onSubmit 属性为提交事件指定处理函数 <form onSubmit={ this.handleSubmit }> {/* type 属性指定 input 元素的类型 */} {/* ref 属性用于从 DOM 节点获取表单元素的值 */} 您的姓名:<input type="text" ref={ this.nameInput } /><br /><br /> 您的手机:<input type="text" ref={ this.phoneInput } /><br /><br /> <input type="submit" value="提交" /> </form> ) } }