0%

ReactDay2—Component

脚手架Scaffold

快速生成项目的工程化结构.每个项目的基本工程化结构是相似的.

PWA(Progressive Web App)

  • PWA是一个网页,可以通过Web技术编写出一个网页应用
  • 随后添加上App Manifest和Service Worker来实现PWA的安装和离线功能

PWA的作用

  • 可以添加至主屏幕,点击主屏幕图标实现动画以及隐藏地址栏

  • 实现离线缓存功能,即使用户手机没网络,依然可以使用一些离线功能

  • 实现消息推送

组件化

划分方式

不同方式可以分成更多类的组件

组件的定义方式:

  • 类组件
  • 函数组件

组件内部是否有状态要维护:

  • 无状态stateless Component
  • 有状态stateful Component

不同的职责

  • 展示型组件Presentational Component
  • 容器型组件(Container Component)

函数组件,无状态组件,展示型组件主要关注UI的展示

类组件,有状态组件,容器型组件主要关注数据逻辑

类组件

  • 名称大写字母开头

  • 需要继承自React.Component

  • 类组件必须实现render函数

render():被调用时,会检查this.props和this.state的变化并返回以下类型之一:

React元素:

  • 通常由JSX创建

  • 会被React渲染为DOM节点, 会被渲染成自定义组件.它们都是React元素

数组/fragments:使得可以返回多个元素

Portals:可以渲染子节点到不同的DOM子树中

字符串或数值类型:在DOM中会被渲染为文本节点

布尔类型或null:什么都不渲染

函数式组件(无hook情况下)

返回值充当render()的角色

  • 无生命周期
  • this关键字不能指向组件实例(因为没有组件实例)
  • 没有内部状态

生命周期

创建到销毁的过程

  • 装载Mount:组件第一次在DOM树中被渲染的过程
  • 更新过程Update:组件状态发生变化,重新更新渲染的过程
  • 卸载过程Unmount:组件从DOM树中被移除的过程

生命周期函数

生命周期函数: React内部为了告诉我们当前处于哪个阶段,会对我们那组件内部实现的某些函数进行回调

componentDidMount:组件挂载到DOM上时,就会回调

  • 依赖DOM的操作就可以在此处进行
  • 发送网络请求最好的地方
  • 添加一些订阅(compponentWillUnmount取消订阅)

componentDidUpdate函数:组件发生更新时,就会回调

  • 组件更新后可以在此次对DOM进行操作
  • 对更新前后的propos进行了比较,也可以选择在此次进行网络请求(当props未发生变化时,则不会执行网络请求)

componentWillUnmount函数:组件即将被移除时,就会回调

  • 执行必要的清理操作
  • 清除timer,取消网络请求,清除在componentDidMount()中创建的订阅

不常用的生命周期函数

  • getSnapshowBeforeUpdate:在React更新DOM之前回调的一个函数,可以获取DOM更新前的一些信息比如滚动位置
  • shouldComponentUpdate:性能优化

组件嵌套

App的组件是Header, Main, Footer组件的父组件

Main组件是Banner,PorductList的父组件

组件通信

  • App中使用了多个Header,每个地方Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示
  • 在Main中请求了Banner数据和ProductList数据,那么就需要传递给他们进行展示
  • 子组件中发生了事件,需要父组件拉力完成某些操作,那么就需要子组件向父组件传递事件

父组件通过 属性=值的形式来传递给子组件数据

子组件通过props参数来获取父组件传递过来的数据

父传子

1
2
3
4
5
6
7
8
9

render() {
const {banners} = this.state
return (
<div className='main'>
<MainBanner banners={banners} title="xixihaha"/>
<MainProductList/>
</div>
)

propTypes

对于传递给子组件的数据,有时候我们可能希望验证

类型验证和传入默认值

1
2
3
4
5
6
7
8
MainBanner.propTypes = {
banners: PropTypes.array.isRequired,
title:PropTypes.string
}
MainBanner.defaultProps = {
banners: [],
title:"默认标题"
}

子传父

通过props传递消息,让父组件给子组件传递一个回调函数,在子组件调用这个函数即可.

插槽slot实现

抽取一个组件,不能将组件中的内容限制为固定的div,span等等

让使用者决定某一块区域放什么内容.

实现方法:

  • 组件的children

    • 注意只有一个插槽时,children只有一个.

      因此弊端: 通过索引值获取传入的元素很容易出错,不能精准的获取传入的原生

  • props属性传递React元素 (常用)

  • 作用域插槽,函数回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//1.组件的children
export class App extends Component {
render() {
return (
<div>
<NavBar>
<button>1</button>
<button>2</button>
<button>3</button>
</NavBar>

export class NavBar extends Component {
render() {
const { children } = this.props
return (
<div className='nav-bar'>
<div className="left">{children[0]}</div>
<div className="center">{children[1]}</div>
<div className="right">{children[2]}</div>
</div>
)
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//2.props属性传递React元素


export class App extends Component {

//根据子组件中的内容决定父组件的tag
getTabItem(item){
if(item==="xixi"){
return<span>{item}</span>
}else{
return <i>{item}</i>
}

}
render() {
return (
<div>
<NavBar leftSlot={item => <button>{item}</button>} centerSlot= {item => <button>{item}</button>} rightSlot={item => this.getTabItem(item)} />
</div>
)
}
}


export class NavBar extends Component {
render() {
const {leftSlot,centerSlot,rightSlot} = this.props
return (
<div className='nav-bar'>
<div className="left">{leftSlot(数据)}</div>
<div className="center">{centerSlot(数据)}</div>
<div className="right">{rightSlot(数据)}</div>
</div>
)
}
}

Context应用场景

跨多组件进行共享(地区偏好,UI主题,用户登录状态,用户信息)\

createContext

方案一:

  1. 创建一个context 单独的文件,使用React.createContext
  2. 在父元素中,通过ThemeContext.Provider中的value属性为后代传递数据
  3. 在子组件导入context单独文件,并将该Context导入,即可以使用ThemeContext中Value的数据

遇到组件需要多个Context场景:需要使用Context.Consumer特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//1.创建context
import React from "react"
const ThemeContext = React.createContext()

export default ThemeContext


//2.调用Provider
export class App extends Component {
constructor() {
super()
this.state = {
info:{name:"alug", age:30}
}
}
render() {
const { info } = this.state

return (
<div>
<UserContext.Provider value={{color:"red", size:"30"}}>
<ThemeContext.Provider value={{color:"red", size:"30"}}>
<Home {...info}/>
</ThemeContext.Provider>
</UserContext.Provider>
</div>
)
}
}

//3. context中取值
export class HomeInfo extends Component {
render() {
console.log(this.context);
return (
<div>
<h2>HomeInfo {this.context.color}</h2>

<UserContext.Consumer>
{
value => {
return <h2>Info User: {value.color}</h2>
}
}
</UserContext.Consumer>
</div>
)
}
}

HomeInfo.contextType = ThemeContext

事件总线的外部库 hy-event-store

创建一个event-store对象A, 子组件通过A.emit给父组件发送数据,父组件通过A.on监听.

通常监听设置componentDidMount中,然后在componentwillUnmount()中取消监听

-------------本文结束感谢您的阅读-------------