脚手架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
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
| 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
|
export class App extends Component {
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
方案一:
- 创建一个context 单独的文件,使用React.createContext
- 在父元素中,通过ThemeContext.Provider中的value属性为后代传递数据
- 在子组件导入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
| import React from "react" const ThemeContext = React.createContext()
export default ThemeContext
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> ) } }
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()中取消监听