目录
React组件介绍
React组件的两种创建方式
使用函数创建组件
函数组件
渲染函数组件
示例
使用类创建组件
抽离为独立的JS文件
步骤
问题记录
React事件处理
事件绑定
记录问题
事件对象
有状态组件和无状态组件
无状态组件(木偶组件)特点
有状态组件的特点
组件中的state和setState()
state的基本使用
setState()修改状态
事件绑定this指向
1.箭头函数
2.Function.prototype.bind()
3.class的实例方法
总结
表单处理
受控组件
步骤
多个受控组件的实例
多表单元素优化步骤
非受控组件
使用步骤
总结
React组件介绍
- 组件化是React的核心思想
- 组件可以实现页面中的部分功能
- 组合多个组件可以实现完整的页面功能
- 特点:可复用、独立、可组合
React组件的两种创建方式
使用函数创建组件
函数组件
使用JS的函数(或箭头函数)创建的组件
约定1:函数名称必须以大写字母开头
约定2:函数组件必须有返回值,表示该组件的结构。如果不需要返回内容需要写返回null
渲染函数组件
用函数名作为组件标签名
组件渲染可以是单标签也可以是双标签
示例
function Hello() {
return (
<div>这是我的第一个函数组件!</div>
)
}
ReactDOM.render(<Hello/>,document.getElementById('component'))
在新的js文件中写入代码,在index.js导入新建的js文件,在index.html中添加id为component的div,将函数组件渲染到component节点上。
使用类创建组件
类组件:使用ES6的class创建的组件
约定1:类名称也必须以大写字母开头
约定2:类组件应该继承React.Component父类,从而可以使用父类中提供的方法或者属性
约定3:类组件必须提供render()方法
约定4:render()方法必须有返回值,表示该组件的结构
class Hello extends React.Component{
render() {
return (
<div>这是我的第一个类组件,哈哈哈哈</div>
)
}
}
ReactDOM.render(<Hello/>,document.getElementById('component2'))
抽离为独立的JS文件
多个组件存在时,一般都会放到一个单独的JS文件中
步骤
- 创建Demo.js
- 在Demo.js中导入React
- 创建组件(函数或类)
- 在Demo.js中导出该组件
- 在index.js中导入Hello组件
Demo.js
//创建文件
// 导入React
import React from 'react'
// 创建组件
class Demo extends React.Component{
render() {
return<div> Hello Class Component!</div>
}
}
// 导出组件
export default Demo
index.js
//导入Demo组件
import Demo from './2抽离为独立的js文件'
// 渲染导入的组件
ReactDOM.render(<Demo/>,document.getElementById('export-component'))
问题记录
在Demo.js中一开始我导入了
import React from 'react'
import ReactDOM from 'react-dom'
之后按照步骤去抽离js文件,结果出现报错和警告,报错是
Parsing error: Identifier 'React' has already been declared.
解析错误,标识符React已经被声明,就是重复导入就会出现解析报错
删除第一行之后
(警告)'ReactDOM' is defined but never used
就是没有使用就不用导入了抽离js并没有在本脚本中渲染组件所以用不着reactdom。
React事件处理
事件绑定
React事件绑定语法与DOM事件语法相似
语法:on+事件名称={事件处理程序},比如onClick={()=>{}}
注意:React事件采用驼峰命名法,比如:onMouseEnter,onFocus
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
handleClick() {
console.log('单击事件触发了')
}
render() {
return (
<button onClick={this.handleClick}>点我</button>
)
}
}
// 渲染组件
ReactDOM.render(<App/>, document.getElementById('shijianbangding'));
不要忘记在index.html创建渲染到的目标(某个div) index.js 引入本js脚本
// 通过函数组件绑定事件
function App() {
function handleClick() {
console.log('通过函数组件绑定函数,单击事件触发了')
}
return (
<button onClick={handleClick}>点我</button>
)
}
记录问题
在函数组件中绑定事件中
// 通过函数组件绑定事件
function App() {
function handleClick() {
console.log('通过函数组件绑定函数,单击事件触发了')
}
return (
<button onClick={this.handleClick}>点我</button>
)
}
Line 17:14: 'handleClick' is defined but never used
事件对象
可以通过事件处理程序的参数获取到事件对象
React中的事件对象叫做合成事件(对象)
合成事件:兼容所有浏览器,无需担心跨浏览器兼容性问题
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
handleClick(e) {
//阻止浏览器的默认行为
e.preventDefault()
console.log('a标签的单击事件触发了')
}
render() {
return (
<a href='http://www.baidu.com' onClick={this.handleClick}>百度</a>
)
}
}
//渲染组件
ReactDOM.render(<App/>,document.getElementById('shijianduixiang'))
有状态组件和无状态组件
函数组件又叫做无状态组件,类组件又叫做有状态组件
状态(state)即数据
函数组件、无状态组件、展示型组件主要关注UI的展示;
类组件、有状态组件、容器型组件主要关注数据逻辑;
在适合的情况下,我们都应该且必须使用无状态组件。无状态组件不像其他两种方法在调用时会创建新实例,它创建时始终保持了一个实例,避免了不必要的检查和内存分配,做到了内部优化。——摘自《深入 React 技术栈》
无状态组件(木偶组件)特点
- 不能参与组件的各个生命周期的管理
- 不能被实例化
有状态组件的特点
- 用来处理数据或者页面逻辑交互
- 类组件可以维护自身的状态变量,即组件的
state
- 有状态组件组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。
参考文献
浅析React有状态组件和无状态组件 - 简书 (jianshu.com)
组件中的state和setState()
state的基本使用
状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
state的值是对象,表示一个组件中可以有多个数据
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
//constructor() {
//super()//ES6要求
//初始化state
// this.state = {
// count:2023
// }
//}
// 简化语法
state = {
count:2023
}
render() {
return (
<div>
<h1>计数器:{ this.state.count}</h1>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<App/>,document.getElementById('state'))
显示结果
初始化state
constructor() {
super()//ES6要求
//初始化state
this.state = {
count:2023
}
根据ES6简化语法(推荐)
state = {
count:2023
}
setState()修改状态
- 状态是可变的
- 语法:this.setState({要修改的数据})
- 注意:不要直接修改state中的值
- 作用:1.修改state 2.更新UI
render() {
return (
<div>
<h1>计数器:{this.state.count}</h1>
<button onClick={() => {
this.setState({
count:this.state.count+1
})
}}>+1</button>
</div>
)
}
JSX中掺杂过多JS逻辑代码,非常混乱,因此,把逻辑代码抽离到单独的方法中,保证JSX结构清晰。
记录问题
//事件处理程序 onIncrement() { console.log('事件处理程序中的this:', this); this.setState({ count:this.state.count+1 }) } render() { return ( <div> <h1>计数器:{this.state.count}</h1> <button onClick={this.onIncrement}>+1</button> </div> ) }
原因:事件处理程序中的this值是undefined
希望:this指向组件实例(render方法中的this即为组件实例)
改正后的代码在下一节
事件绑定this指向
1.箭头函数
利用箭头函数自身不绑定this的特点
render()方法中的this为组件实例,可以获取到setState()
import React from 'react'
import ReactDOM from 'react-dom'
class Arrow extends React.Component{
state = {
count:2023
}
//事件处理程序
onIncrement1() {
console.log('事件处理程序中的this:', this);
this.setState({
count:this.state.count+1
})
}
render() {
return (
<div>
<h1>计数器:{this.state.count}</h1>
<button onClick={()=>this.onIncrement1()}>+1</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<Arrow/>,document.getElementById('jiantou'))
在改bug的时候,没有任何报错,button无效,最后发现是onIncrement方法没有写(),😓
2.Function.prototype.bind()
利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起
constructor() {
super()
this.onIncrement=this.onIncrement.bind(this)
}
import React from 'react'
import ReactDOM from 'react-dom'
class Bind extends React.Component{
state = {
count:2023
}
constructor() {
super()
this.onIncrement=this.onIncrement.bind(this)
}
//事件处理程序
onIncrement() {
console.log('事件处理程序中的this:', this);
this.setState({
count:this.state.count+1
})
}
render() {
return (
<div>
<h1>计数器:{this.state.count}</h1>
<button onClick={this.onIncrement}>bind+1</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<Bind/>,document.getElementById('bind'))
3.class的实例方法
利用箭头函数形式的class实例方法
注意:该语法是实验性语法,但是,由于babel的存在可以直接使用
//事件处理程序
onIncrement=() =>{
console.log('事件处理程序中的this:', this);
this.setState({
count:this.state.count+1
})
}
总结
1.推荐使用class的实例方法
class Hello extends React.Component{
onIncrement = () => {
this.setState({……})
}
}
2.箭头函数
< button onClick = {()=> this.inCrement()}/>
3.bind
constructor(){
super()
this.onIncrement=this.onIncrement.bind(this)
}
表单处理
受控组件
html中的表单元素是可输入的,有自己的可变状态
react的可变状态通常保存在state中,并且只能通过setState()方法来修改
React将state与表单元素值value绑定到一起,由state的值来控制表单元素的值
<input type="text" value={this.state.txt} />
步骤
1.给state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
2.给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)
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}></input>
</div>
)
}
}
多个受控组件的实例
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
state = {
txt: '',
content: '',
city: 'sh',
isChecked:false
}
// 处理文本框的变化
handleChange = e => {
this.setState({
txt:e.target.value
})
}
// 处理富文本框的变化
handleContent = e => {
this.setState({
content:e.target.value
})
}
// 处理下拉框的变化
handleCity = e => {
this.setState({
})
}
render() {
return (
<div>
{/* 文本框 */}
<input type='text'value={this.state.txt} onChange={this.handleChange}></input>
<br />
{/* 富文本框 */}
<textarea value={this.state.content} onChange={this.handleContent}></textarea>
<br />
{/* 下拉框 */}
<select value={this.state.city} onChange={this.handleCity}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
</select>
<br />
{/* 复选框 */}
<input type="checkbox"></input>
</div>
)
}
}
//渲染组件
ReactDOM.render(<App/>,document.getElementById('biaodan2'))
多表单元素优化步骤
1.给表单元素添加name属性,名称和state相同
<input type='text' name='txt' value={this.state.txt} onChange={this.handleChange}></input>
2.根据表单元素获取对应值
// 根据表单元素类型获取值
const value = target.type === 'checkbox'
? target.checked
: target.value
//根据name设置对应state
this.setState({
[name]:value
})
3.在change事件处理程序中通过[name]来修改对应的state
handleForm = e => {
//获取当前DOM 对象
const target = e.target
//根据类型获取值
const value = target.type === 'checkedbox'
? target.checked
: target.value
//获取name
const name = target.name
this.setState({
//中括号是动态获取,因为name值不同
[name]:value
})
}
render() {
return (
<div>
{/* 文本框 */}
<input type='text' name='txt' value={this.state.txt} onChange={this.handleForm}></input>
<br />
{/* 富文本框 */}
<textarea value={this.state.content} onChange={this.handleForm}></textarea>
<br />
{/* 下拉框 */}
<select value={this.state.city} onChange={this.handleForm}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
</select>
<br />
{/* 复选框 */}
<input name='isChecked' type="checkbox" checked={this.state.isChecked} onChange={this.handleForm}></input>
</div>
)
}
非受控组件
使用步骤
1.调用React.createRef()方法创建一个ref对象
constructor(){
super()
this.txtRef=React.createRef()
}
2.将创建好的ref对象添加到文本框中
<input type="text" ref={this.txtRef} />
3.通过ref对象获取到文本框的值
console.log(this.txtRef.current.value)
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
constructor() {
super()
// 创建ref
this.txtRef=React.createRef()
}
// 获取文本框的值
getTxt = () => {
console.log('文本框的值为:', this.txtRef.current.value);
}
render() {
return (
<div>
<input type="text" ref={this.txtRef} />
<button onClick={this.getTxt}>获取到文本框的值</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<App />, document.getElementById('biaodan3'))
React一般不直接操作DOM,所以非受控组件并不常用
总结
- 组件的两种创建方式:函数组件和类组件
- 无状态(函数)组件,负责静态结构展示
- 有状态(类)组件,负责更新UI
- 绑定事件注意this指向的问题
- 推荐使用受控组件来处理表单