什么是组件,组件的特点及分类
组件
组件是指对特定功能的封装,主要用来对UI进行拆分。
特点
- 独立
- 可复用
- 可组合
分类
- 基础组件:指
input、button这种基础标签,以及antd封装过的通用UI组件 - 业务组件:由基础组件组合成的业务抽象化UI。例如: 包含了A公司所有部门信息的下拉框
- 区块组件:由基础组件组件和业务组件组合成的UI块
- 页面组件:展示给用户的最终页面,一般就是对应一个路由规则
React 组件的两种创建方式
(1)使用 JS 中的函数创建组件
(2)使用 JS 中的 class 创建组件
import React from 'react'
import ReactDOM from 'react-dom'
const title = <h1>react的两种定义组件的方式</h1>
// 定义一个函数式组件
const Com1 = () => {
return <div>第一个函数式组件</div>
}
// 定义一个类组件
class Com2 extends React.Component {
render () {
return <div>第一个类组件</div>
}
}
const content = (
<div>
{title}
// 使用双标签渲染
<Com1></Com1>
<hr />
// 使用单标签渲染
<Com2 />
</div>
)
ReactDOM.render(content, document.getElementById('root'))
函数式组件-使用 JS 的函数(或箭头函数)创建的组件
默认约定
- 函数名首字符大写(必须以大写字母开头,React 据此区分
组件和普通的 HTML) - 必须有返回值(表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null)
// 1. 使用普通函数创建组件:
function Hello() {
return <div>这是我的第一个函数组件!</div>
}
// 2. 使用箭头函数创建组件:
const Hello = () => <div>这是我的第一个函数组件!</div>
类组件-用class创建组件
格式
// import { Component } from 'react'
// class 类名 extends Component {
import React form 'react'
class 类名 extends React.Component {
// ...
render () {
return 本组件的UI结构
}
}
注意点
- 类名必须以大写字母开头
- extends是一个关键字,用来实现类之间的继承。类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性。
- 类组件必须提供 render 方法,render 方法必须有返回值,表示该组件的 UI 结构。render会在组件创建时执行一次
有状态组件和无状态组件
什么是状态(state)
状态是指用来描述事物在某一时刻的形态的数据.(例如:11月12日时书的库存数量)
特点
状态能被改变,改变了之后视图会有对应的变化
什么是有状态组件和无状态组件
-
有状态组件:能定义state的组件。类组件就是有状态组件。
-
无状态组件:不能定义state的组件。函数组件又叫做
无状态组件(注:2019年02月06日,react 16.8中引入了 React Hooks,从而函数式组件也能定义自己的状态了)
类组件的状态
定义状态的两种方式
(1)state = 对象
(2)在构造器中用this.state= 对象来做初始化
import React from "react";
export default class Hello extends React.Component {
// 1. state就是状态
state = {
list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
isLoading: true
};
// 2. 构造函数
constructor() {
this.state = {
list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
isLoading: true
}
}
}
在视图中使用
render() {
return (
<>
<h1>歌单-{this.state.count}</h1>
<ul>
{this.state.list.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<div>{this.state.isLoading ? "正在加载" : "加载完成"}</div>
</>
);
}
事件绑定
格式
<元素 事件名1={ 事件处理函数1 } 事件名2={ 事件处理函数2 } ></元素>
(注:React 事件名采用驼峰命名法,比如:onMouseEnter、onFocus、 onClick ......)
import React from 'react'
import ReactDOM from 'react-dom'
const title = <h1>react中的事件</h1>
export default class Hello extends React.Component {
fn() {
console.log('mouseEnter事件')
}
render() {
return (
<div
onClick={() => console.log('click事件')}
onMouseEnter={this.fn}
能处理鼠标进入或者点击事件
</div>
)
}
}
const content = (
<div>
{title}
{<Hello />}
</div>
)
ReactDOM.render(content, document.getElementById('root'))
注意:
- 事件名是小驼峰命名格式
- 在类中补充方法
- this.fn不要加括号
事件对象
react中,通过事件处理函数的形参来获取。
handleClick(e)=> {
e.preventDefault()
console.log('单击事件触发了', e)
}
render() {
return (<div>
<button onClick={(e)=>{console.log('按钮点击了', e)}}>按钮</button>
<a href="http://itcast.cn/" onClick={this.handleClick}>武汉黑马</a>
</div>)
}
}
事件处理-this指向问题
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick() {
console.log(this) // 这里的this是?undefined
}
render() {
console.log(this) // 这里的this是?当前react组件
return (
<div>
//this.handleClick并没有调用,其没有绑定调用的事件源,在严格模式下指向的并不是window
<button onClick={this.handleClick}>点我</button>
</div>
)
}
}
分析原因
- 事件处理程序的函数式函数调用模式,在严格模式下,this指向
undefined - render函数是被组件实例调用的,因此render函数中的this指向当前组件
事件处理-this指向解决方案
(1)在外层补充箭头函数(原理:箭头函数中的this指向外层作用域中的this)
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick() {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={() => {this.handleClick()}}>点我</button>
</div>
)
}
}
(2)Function.prototype.bind()(原理:bind能绑定this)
class App extends React.Component {
state = {
msg: 'hello react'
}
handleClick() {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>点我</button>
</div>
)
}
}
(3)class 的实例方法【推荐】
class App extends React.Component {
state = {
msg: 'hello react'
}
// class 的实例方法
handleClick = () => {
console.log(this.state.msg)
}
render() {
return (
<div>
<button onClick={this.handleClick}>点我</button>
</div>
)
}
}
组件的状态-修改状态
setState
语法:this.setState({ 要修改的部分数据 })
作用: 修改state; 更新UI
state = {
count: 0
};
this.setState({
count: this.state.count++
})
注: react核心理念之状态不可变
不要直接修改当前状态值,而是创建新的状态值去覆盖老的值。
获取表单元素的值的两种思路
- 直接找到表单元素进行dom操作 --> 非受控组件
- 将表单元素值与react的state绑定到一起,把用户的修改同步到state中。让组件受到react的控制--> 受控组件
非受控组件-ref
使用步骤:
(1)导入方法。import { createRef } from 'react'
(2)调用createRef方法创建引用,假设名为refDom。 const refDom = createRef()
(3)refDom设置给表单元素的ref属性。<input ref={refDom}/>
(4)通过refDom.current.value来获取值。console.log(this.refDom.current.value)
// 1. 导入方法
import { createRef } from 'react'
class Hello extends Component {
// 2. 调用createRef方法创建引用
txtRef = createRef()
handleClick = () => {
// 4. 通过.current.value来获取值
console.log(this.txtRef.current.value)
}
render() {
return (
<div>
<h1>如何获取input中的值-非受控组件-ref</h1>
{/* 3. 设置给表单元素的ref属性 */}
<p><input type="text" ref={this.txtRef}/></p>
<button onClick={handleClick}>获取文本框的值</button>
<div>
)
}
}
受控组件
使用步骤:
-
在state中定义状态
-
对表单元素做两件事
(1)设置value为上面定义的状态
(2)绑定onChange事件,并在回调中通过setState来修改状态值
class App extends React.Component {
state = {
// 1. 在state中定义状态
msg: 'hello react'
}
handleChange = (e) => {
this.setState({
msg: e.target.value
})
}
handleClick = ()=> {
console.log(this.state.msg)
}
render() {
return (
<div>
<h1>如何获取input中的值-受控组件</h1>
<p>
{/* 2. 对表单元素做两件事 */}
<input type="text"
value={this.state.msg}
onChange={this.handleChange}
/>
</p>
<button onClick={handleClick}>获取文本框的值</button>
<div>
)
}
}
常见的受控组件
不同类型的表单元素进行受控处理时的格式是不同的:
(1)文本框、文本域、下拉框:value属性 + onChange事件
(2)复选框: checked属性 + onChange事件
(3)单选按钮组:checked属性 + onChange事件
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
username: '',
desc: '',
city: '2',
isSingle: true,
gender: '男'
}
handleName = (e) => {
this.setState({
username: e.target.value
})
}
handleDesc = (e) => {
this.setState({
desc: e.target.value
})
}
handleCity = (e) => {
this.setState({
city: e.target.value
})
}
handleSingle = (e) => {
this.setState({
isSingle: e.target.checked
})
}
hGender = (e) => {
this.setState({
gender: e.target.value
})
}
render () {
return (
<div>
姓名:<input
type="text"
value={this.state.username}
onChange={this.handleName}
/>
<br />
描述:<textarea value={this.state.desc} onChange={this.handleDesc} />
<br />
城市:<select value={this.state.city} onChange={this.handleCity}>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
<option value="4">深圳</option>
</select>
<br />
是否单身:<input
type="checkbox"
checked={this.state.isSingle}
onChange={this.handleSingle}
/>
<br />
<input
type="radio"
name="gender"
value="男"
checked={this.state.gender === '男'}
onChange={this.hGender}
/>{' '}
男
<input
type="radio"
name="gender"
value="女"
checked={this.state.gender === '女'}
onChange={this.hGender}
/>{' '}
女
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))