本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
React 组件介绍
- 组件是 React 的
一等公民,使用 React 就是在用组件。 - 组件表示页面中的部分功能。
- 组合多个组件实现完整的页面功能。
- 特点:
- 可复用。
- 独立性。
- 可组合。
React 组件的两种创建方式
使用函数创建组件:
-
函数组件:使用 JS 的函数(或建瓯函数)创建的组件
- 约定一:函数名称必须以大写字母开头。
- 约定二:函数组件必须有返回值,表示该组件的结构。
- 如果返回值是 null ,表示不渲染任何内容。
function Hello () { return ( <div>这是我的第一个函数组件!</div> ) } -
渲染函数组件:用函数名作为组件标签名。
- 组件标签可以是单标签也可以是双标签。
function Hello () { return ( <div>这是我的第一个函数组件!</div> ) } // 渲染 ReactDOM.render(<Hello />, document.querySelector('#root')- 用箭头函数创建组件:
const Hello = () => <div>这是我的第一个函数组件</div> // 这个渲染的效果等同于上面的那个函数创建的组件。 -
总结:
- 使用 JS 中的函数创建的组件叫做:函数组件。
- 函数组件必须有返回值。
- 组件名称必须以大写字母开头,React 据此区分 组件 和 普通的 React 元素。
- 使用函数名作为组件标签名。
使用类创建组件:
-
类组件:使用 ES6 的 class 创建的组件。
- 约定一:类名称也必须以大写字母开头。
- 约定二:类组件应该继承 React.Component 父类,从而可以使用父类中提供的方法或属性。
- 约定三:类组件必须提供 render() 方法。
- 约定四:render() 方法必须有返回值,表示该组件的结构。
class Hello extends React.Component { render () { return <div>Hello Class Component!</div> } } ReactDOM.render(<Hello />, document.querySelector('#root')
抽离为独立 JS 文件
-
思考:项目中的组件多了以后,该如何组织这些组件呢?
- 选择一:将所有组件放在同一个 JS 文件中。
- 选择二:将每个组件放到单独的 JS 文件中。
-
组件作为一个独立的个体,一般都会放到一个单独的 JS 文件中。
-
抽离组件的步骤:
- 创建 Hello.js 文件。
- 在 Hello.js 中导入 React 。
- 创建组件(函数组件或类组件)。
- 在 Hello.js 中导出该组件。
- 在 index.js 中导入 Hello 组件。
- 渲染组件。
// Hello.js 文件 import React from 'react' class Hello extends React.Component { render () { return <div>Hello Class Component!</div> } } // 导出 Hello 组件 export default Hello// index.js 文件 import Hello from './Hello' // 渲染导入的 Hello 组件 ReactDOM.render(<Hello />, document.querySelector('#root')
React 事件处理
事件绑定
-
React 事件绑定语法与 DOM 事件语法相似。
-
语法:
-
on + 事件名称 = {事件处理程序} -
比如:
onClick={() => {}}
-
-
注意:**React 事件采用
驼峰命名法,比如:onMouseEnter、onFocus 。// 通过类创建组件 class App extends React.Component { handleClick() { console.log('单击事件触发了') } render() { return ( <button onClick={this.handleClick}>点我</button> ) } }// 通过函数创建组件 function App () { function handleClick() { console.log('单击事件触发了') } return ( <button onClick={this.handleClick}>点我</button> ) }
事件对象
-
可以通过事件处理程序的参数获取到事件对象。
-
React 中的事件对象叫做:
合成事件(对象)。 -
合成事件:兼容所有浏览器,无需担心跨域浏览器兼容性问题。
function handleClick(e) { e.preventDefault() console.log('事件对象',e) } <a onClick={handleClick}>点我不会跳转页面</a> -
具体使用:
function App() { function handleClick(e) { // 阻止浏览器的默认行为 e.preventDefault() console.log('事件对象',e) } return( <a href="www.baidu.com" onClick={handleClick}>点击页面不跳转</a> ) } // 渲染react元素 ReactDOM.render(<App />, document.querySelector('#root'))
有状态组件和无状态组件
- 函数组件又叫做无状态组件,类组件又叫做有状态组件。
- 状态(state)即数据。
- 函数组件没有自己的状态,只负责数据展示(静)。
- 类组件有自己的状态,负责更新 UI ,让页面“动”起来。
- 比如计数器案例中,点击按钮让数值加1.0和1就是不同时刻的状态,而由0变1就表示状态发生了变化。状态变化后,UI 也要相应的更新。React 中想要实现该功能,就要使用有状态组件来完成。
组件中的 state 和 setState
state 的基本使用
-
状态(state)即数据,是组件内部的私有数据,只能在组件内部使用。
-
state 的值是对象,表示一个组件中可以有多个数据。
class App extends React.Component { constyuctor() { super() // 初始化 state this.state = { count: 0 } } // 简化写法(推荐) state = { count: 0 } render(){ return ( <div> <h1>计数器:{this.state.count}</h1> </div> ) } } ReactDOM.render(<App />, document.querySelector('#root')) -
总结:
- 状态即数据。
- 状态是私有的,只能在组件内部使用。
- 通过
this.state来获取状态。
setState() 修改状态
-
状态是可变的。
-
语法:
this.setState({要修改的数据})
-
注意:不要直接修改 state 中的值,这是错误的!!!
// 正确 this.setState({ count: this.state.count + 1 }) // 错误 this.state.count += 1 -
setState() 的作用:
- 修改 state 。
- 更新 UI 。
-
思想:数据驱动视图。
从 JSX 中抽离事件处理程序
-
JSX 中掺杂过多 JS 逻辑代码,会显得非常混乱。
-
推荐:将逻辑抽离到单独的方法中,保证 JSX 结构清晰。
-
原因:事件处理程序中 this 的值为 undefined 。
-
希望:this 指向组件实例(render 方法中的 this 即为组件实例)
事件绑定 this 指向
箭头函数
-
利用箭头函数自身不绑定 this 的特点。
-
render() 方法中的 this 为组件实例,可以获取到 setState() 。
class App extends React.Component { state = { count: 0 } onIncrement() { this.setState({ count: this.state.count + 1 }) } render() { // 箭头函数中的 this 指向外部环境,此处为:render() 方法。 return ( <div> <h1>总数:{this.state.count}</h1> <button onClick={() => this.onIncrement()}>+1</button> </div> ) } }
Function.prototype.bind()
-
利用 ES5 中的 bind 方法,将事件处理程序中的 this 与组件实例绑定到一起。
class App extends React.Component { constructor() { super() this.state = { count: 0 } this.onIncrement = this.onIncrement.bind(this) } onIncrement() { this.setState({ count: this.state.count + 1 }) } render() { // 箭头函数中的 this 指向外部环境,此处为:render() 方法。 return ( <div> <h1>总数:{this.state.count}</h1> <button onClick={this.onIncrement}>+1</button> </div> ) } }
class 的实例方法
-
利用箭头函数形式的 class 实例方法。
-
注意:该语法是实验性语法,但是,由于 babel 的存在可以直接调用。
class App extends React.Component { state = { count: 0 } onIncrement = () => { this.setState({ count: this.state.count + 1 }) } render() { return ( <div> <h1>总数:{this.state.count}</h1> <button onClick={this.onIncrement}>+1</button> </div> ) } }
总结
-
推荐:使用 class 的实例方法。
class Hello extends React.Component { onIncrement = () => { this.setState({...}) } } -
箭头函数。
<button onClick={() => this.onIncrement()}>+1</button> -
bind
constructor() { super() this.onIncrement = this.onIncrement.bind(this) }
表单处理
受控组件
-
HTML 中的表单元素是可输入的,也就是有自己的可变状态。
-
而 React 中可变状态通常保存在 state 中,并且只能通过 setState() 方法来修改。
-
React 将 state 与表单元素的 value 绑定到了一起,由 state 的值来控制表单元素的值。
<input type="text" value={this.state.txt} /> -
受控组件:其值受到 React 控制的表单元素。
-
步骤:
-
在 state 中添加一个状态,作为表单元素的 value 值(控制表单元素值的来源)。
state = { txt: '' }<input type="text" value={this.state.txt} /> -
给表单元素绑定 change 事件,将表单元素的值设置为 state 的值(控制表单元素值的变化)。
<input type="text" value={this.state.txt} onChange={e => this.setState({ txt: e.target.value })} />
-
-
实例:
- 文本框
class App extends React.Component { state = { txt: '' } handleChange = e => { this.setState({ txt: e.target.value }) } render() { return ( <div> <input type="text" value={this.state.txt} onChange={this.handleChange} /> <h2>{this.state.txt}</h2> </div> ) } }- 富文本框、下拉框
class App extends React.Component { state = { content: '' } handleContent = e => { this.setState({ content: e.target.value }) } render() { return ( <div> <input type="text" value={this.state.content} onChange={this.handleContent} /> <h2>{this.state.content}</h2> </div> ) } }- 下拉框
class App extends React.Component { state = { city: 'sh' } handleCity = e => { this.setState({ city: e.target.value }) } render() { return ( <div> <select value={this.state.city} onChange={this.handleCity}> <option value="bj">北京</option> <option value="sh">上海</option> <option value="gz">广州</option> </select> <h2>{this.state.city}</h2> </div> ) } }- 复选框
class App extends React.Component { state = { isChecked: true } handleChecked = e => { this.setState({ isChecked: e.target.checked }) } render() { return ( <div> <input type="checkbox" checked={this.state.isChecked} onChange={this.handleChecked} /> </div> ) } }
示例总结
- 文本框、富文本框、下拉框操作 value 属性。
- 复选框操作 checked 属性。
多表单元素优化
-
问题:每个表单元素都有一个单独的事件处理程序处理太繁琐。
- 优化:使用一个事件处理程序同时处理多个表单元素。
-
步骤:
-
给表单元素添加 name 属性,名称与 state 相同。
<input type="text" name="txt" value={this.state.txt} onChange={this.handleForm} /> -
根据表单元素类型获取对应值。
// 根据表单元素类型获取值 const value = target.type === 'checkbox' ? target.checked : target.value // 根据 name 设置对应 state this.setState({ [name]: value }) -
在 change 事件处理程序中通过 [name] 来修改对应的 state 。
-
-
实例:
class App extends React.Component { state = { txt: '', content: '', city: 'sh', isChecked: true } handleForm = e => { // 获取当前 DOM 对象 const target = e.target // 根据类型获取值 const value = target.type === 'checkbox' ? target.checked : target.value // 获取 name const name = target.name this.setState({ [name]: value }) } render() { return ( <div> <input name="txt" type="text" value={this.state.txt} onChange={this.handleForm} /> <br/> <h1>{this.state.txt}</h1> <textarea name="content" type="checkbox" checked={this.state.content} onChange={this.handleForm} /> <br/> <h1>{this.state.content}</h1> <select name="city" value={this.state.city} onChange={this.handleForm}> <option value="bj">北京</option> <option value="sh">上海</option> <option value="gz">广州</option> </select> <br/> <h1>{this.state.city}</h1> <input name="isChecked" type="checkbox" checked={this.state.isChecked} onChange={this.handleForm} /> <br/> <h1>{this.state.isChecked}</h1> </div> ) } }
非受控组件
-
使用步骤:
-
调用 React.createRef() 方法创建一个 ref 对象。
constructor() { super() this.txtRef = React.createRef() } -
将创建好的 ref 对象添加到文本框中。
<input type="text" ref={this.txtRef} /> -
通过 ref 对象获取到文本框的值。
console.log(this.txtRef.current.value) -
大多数情况下使用受控组件。
-
总结
- 组件的两种创建方式:函数组件和类组件。
- 无状态(函数)组件,负责静态结构展示。
- 有状态(类)组件,负责更新 UI ,让页面动起来。
- 绑定事件注意 this 指向。
- 推荐使用受控组件来处理表单。
- 完全利用 JS 语言的能力创建组件,这是 React 的思想。