一、React进阶
1、React脚手架
npx create-react-app my-app
2、react
const React = {
createElement,
Component
}
React.createElement: 创建虚拟DOM
React.Component: 实现自定义组件
3、react-dom
主要是render逻辑。
ReactDOM.render: 渲染真实DOM
4、Redux
5、组件通讯
props
使用:函数组件通过props接收数据,类组件通过this.props接收数据。
特点:传递任意类型的数据;props是只读的对象;
props深入
- children属性
- props校验
Mouse.propTypes = {
children: PropTypes.func.isRequired
}
- props默认值
Mouse.defaultProps = {
children: ""
}
三种方式
- 父传子
- 子传父
通过回调函数实现
class Parent extends React.Component{
getMsgCallback = data=>{
console.log(data)
}
render(){
return (
<div>
<Child getMsgCallback={this.getMsgCallback}>
</div>
)
}
}
class Child extends React.Component{
handleClick= ()=>{
this.props.getMsgCallback("子传父")
}
render(){
return (
<div>
<button onClick={this.handleClick}/>
</div>
)
}
}
- 兄弟组件
状态提升
Context
跨组件传递数据
const {Provider,Consumer}=React.createContext()
<Provider value="">
</Provider>
<Consumer>
{data => {}}
</Consumer>
6、组件的生命周期
- 只有类组件才有生命周期
- 不能在render钩子函数中调用setState函数
- 在componentDidUpdate钩子函数中调用setState函数,要比较更新前后的状态是否相同
常用钩子函数:
旧版钩子函数:
新版钩子函数:
7、render props模式
实现状态逻辑复用,状态指的是state,逻辑指的是setState。
class Mouse extends React.Component{
render(){
return this.props.render(this.state)
}
}
<Mouse render={(mouse)=><p>鼠标当前位置{mouse.x},{mouse.y}</p>}/>
children代替render属性
class Mouse extends React.Component{
render(){
return this.props.children(this.state)
}
}
<Mouse>
{(mouse)=><p>鼠标当前位置{mouse.x},{mouse.y}</p>}
</Mouse>
添加props校验
import PropTypes from 'prop-types'
Mouse.propTypes = {
children: PropTypes.func.isRequired
}
8、高阶组件
高阶组件之于组件相当于手机壳之于手机。
- 目的:实现状态逻辑复用
- 装饰模式
- HOC,实际上是一个函数
const EnhancedComponent = withHOC(WrappedComponent)
function withMouse(WrappedComponent){
class Mouse extends React.Component{
return <WrappedComponent {...this.state}/>
}
return Mouse
}
const MousePosition = withMouse(Position)
<MousePosition/>
问题1
得到两个组件名称相同
解决1
设置displayName能在调试时区分不同组件
Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`
function getDisplayName(WrappedComponent){
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}
问题2
props丢失
解决2
<WrappedComponent {...this.state} {...this.props}/>
二、React原理
1、setState函数
作用:修改state;更新组件
注意:
异步更新数据;
多次调用setState函数只触发一次重新渲染;
setState(updater[,callback]),第二个参数在状态更新且页面完成渲染后立即执行某个操作;
// 经典写法
this.setState({
count: this.state.count+1
})
// 推荐写法,多次调用setState函数的顺序更符合人类的思维顺序
this.setState((state,props)=>{
return {
count: state.count+1
}
})
2、JSX语法的转化过程
JSX是createElement函数的简化语法。
JSX语法被@babel/preset-react插件编译为creatElement函数。
React元素:描述看到的内容。
JSX和JSX预处理后的代码:
3、组件更新机制
4、组件性能优化
减轻state
只存储与渲染相关的数据
避免不必要的渲染
使用钩子函数shouldComponentUpdate(nextProps, nextState)
纯组件
自动实现了shouldComponentUpdate钩子函数;
使用浅层对比,对于引用类型,只比较对象的地址;
const newObj = {...state.obj, number: 2}
setState({obj: newObj})
this.setState({
list: [...this.state.list, {新数据}]
})
5、React的部分更新
实现:虚拟DOM配合Diff算法
虚拟DOM:React元素,本质是JS对象,描述UI。用JS对象表示DOM信息和结构,当状态变更的时候,重新渲染这个JS的对象结构
const element={
type: 'h1',
props: {
className: 'greeting',
children: 'Hello JSX'
}
}
Diff过程:
三、React路由
- 功能:从一个视图导航到另一个视图
- 使用:配置路由和组件
- 常用组件:
Router组件,推荐用HistoryRouter
Link组件
Route组件,能够指定路由组件的位置 - 路由的执行过程:
- 编程式导航
通过JS代码实现页面跳转
push(path)
go(n) - 匹配模式
- 模糊匹配
默认匹配模式,pathname以path开头就匹配成功,pathname是Link组件的to,path是Route组件的path - 精确匹配
添加exact属性
- 模糊匹配
<Route exact path="/" component=... />
四、租房移动Web实践
核心业务
在线找房、用户登陆、房源发布
技术栈
React核心库:react、react-dom、react-router-dom
脚手架:create-react-app
数据请求:axios
UI组件库:antd-mobile
其他组件库:react-virtualized、formik+yup、react-spring
百度地图API
node-sass依赖
注意node-sass依赖的问题,多次yarn操作后可以成功安装,但默认情况下node-sass的版本与node的版本不一致。(着实纳闷)
condition:
node -v v14.17.3
node-gyp -v v3.8.0
target:
yarn add node-sass@4.12.0
problem:
gyp verb `which` failed Error: not found: python2
solution:
yarn add global production windows-build-tools
H5的地理位置API
- 获取的地理位置与GPS、IP地址、WIFI和蓝牙的MAC地址、GSM/CDMS的ID有关。手机优先使用GPS定位,笔记本最准确的定位是WIFI。
- 只能获得经纬度信息。
navigator.geolocation.getCurrentPosition(position => {
console.log('当前位置信息:', position)
})
百度地图API
使用步骤:
- 引入百度地图API的JS文件,替换自己的密钥
- 在index.css设置全局样式
- 创建Map组件,配置路由。在Map组件中,创建地图容器元素,并设置样式
- 创建地图实例
- 设置中心点坐标
- 初始化地图,并设置展示级别
地图找房
- 百度地图标注
文本覆盖物label - 缩放级别
- 缩放事件
组件间样式覆盖问题
solution
- 手动处理,定义不同类名
- CSS IN JS
- CSS Modules,React脚手架已集成
说明:对CSS类名重命名,保证每个类名的唯一性。所有类名都有局部作用域。
实现:webpack的css-loader
命名:BEM规范(Block块、Element元素、Modifier)
React脚手架中的命名:文件名、类名、hash - styled-components
- CSS Modules,React脚手架已集成