一、react原理的初步了解:
1)setState()的说明
2)JSX语法转化
3)组件更新机制
4)组件性能优化
5)虚拟DOM和diff算法
1、setState()的说明
作用:修改state,更新UI
1)setState()异步更新数据
this.state = {
a: 0
}
this.setState({
a: this.state.a + 1
})
console.log(this.state.a)
2)多次调用setState(),合并成一次render,提高页面渲染性能;
下面的setState虽然调用两次,但是第二次不能依赖第一次的结果做处理,因为是异步更新
this.state = {
a: 0
}
this.setState({
a: this.state.a + 1 // 0 + 1
})
this.setState({
a: this.state.a + 1 // 0 + 1
})
console.log(this.state.a)} // 0
render() {
return (
<p>fhdufhud</p>
)
}
下面的语法也是异步更新,但是在回调中拿到的是最新的state
this.state = {
a: 0
}
this.setState((state, props) => {
return {
a: state.a + 1 // 0 + 1
}
})
this.setState((state, props) => {
// state是更新后的数据
return {
a: state.a + 1 // 1 + 1
}
})
console.log(this.state.a)} // 0
render() {
return (
<p>fhdufhud</p>
)
}
3)setState第二个参数fn
this.setState((state, props) => {}, () => {console.log('在状态更新之后,立即执行某个操作')})
2、JSX语法转化过程
1)JSX是createElement的语法糖
2)JSX语法被插件@babel/preset-react编译为createElement()方法
3)React元素:对象,描述在DOM上看到的内容
3、组件更新机制
setState()两个作用:修改state、更新UI
过程:父组件重新渲染,也会重新渲染当前组件的子组件
4、组件性能优化
1)减轻state:只存储跟组件渲染相关的数据,不用做渲染的数据不放在state中,因为state里面的数据更新会触发组件的render
对于在多个方法中公用的变量,但是不用于渲染,则放在this中
2)避免不必要的重新渲染
组件更新机制:父组件重新渲染,也会重新渲染当前组件的子组件
问题:子组件没有任何变化也会更新
解决方式:使用钩子函数shouldComponentUpdate(nextProps, nextState)
作用:返回true表示要渲染,false不需要渲染
const { threadId } = require("worker_threads");
shouldComponentUpdate(nextProps, nextState) {
// 更新值和当前值做比较
return nextState.number !== threadId.state.number
}
3) 使用纯组件:React.pureComponent
纯组件React.PureComponent与React.component功能相似
区别:内部实现了shouldComponent钩子,不需要手动比较
原理:纯组件内部分别对比前后两次props state的值,决定是否重新渲染组件
说明:纯组件内部的对比是shallow compare
对于引用类型只比较对象的地址是否相同:注意如果props或者state中属性值为引用类型,需要创建新数据,不要直接修改原数据
const { threadId } = require("worker_threads")
// 对于objetc,创建新数据
const newObj = {...this.state.obj, number: 2}
this.setState({
obj: newObj
})
// 对于array:不要用push pop unshift shift等直接修改原数组的方法
// 用返回新数组的方法:concat slice map 等
this.setState({
list: [...this.state.list, {新数据}]
})
5、虚拟DOM和diff算法
1)更新视图思想:state变化就重新渲染视图
2)理想状态:部分更新,只更新变化地方
3)虚拟DOM本质上上JS对象
执行过程
1)初次渲染,React会根据初始state,创建虚拟DOM对象(树)
2)根据虚拟DOM生成真正的DOM,渲染到页面
3)当数据变化后(setState()),重新根据新的数据,创建新的虚拟DOM对象(树)
4)与上次得到的虚拟DOM对象,用diff算法对比,得到需要更新的内容
5)最后,React只将变化的内容更新(patch)到DOM中,重新渲染到页面
diff算法触发时机
1)组件render后,根据状态和JSX结构,生成虚拟DOM对象
2)diff算法发生在render之后
虚拟DOM的真正价值
虚拟DOM让React脱离了浏览器环境的束缚
二、路由基础学习
1)React路由的作用
2)react-router-dom的基本使用
3)路由的执行过程
4)使用编程式导航跳转路由
5)默认路由
6)React路由的匹配模式
1、React路由的作用
前端路由功能:让用户从一个视图导航到另外一个视图
前端路由是一套映射规则,是URL路径与组件的对应关系
使用React路由就是配置路径和组件(配对)
2、react-router-dom的基本使用
基本使用
1)安装路由包:react-router-dom
npm i react-router-dom
2) 导入路由三个核心组件Router/Route/Link
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
3) 使用Router组件包裹整个应用
<Router>
<div className="app"></div>
</Router>
4) 使用Link组件作为导航菜单(路由入口)
<Link to="/first">page one</Link>
5) 使用Route组件配置路由规则、要展示的组件(路由出口)
const First = () => (<p>page one content</p>)
<Router>
<div className="app">
<Link to="/first">page one</Link>
<Route path="/first" component={First}></Route>
</div>
</Router>
常用组件说明
1)Router组件“包裹整个应用,一个React应用只需要用一次
2)两种常用Router:HashRouter和BrowserRouter
3)hashRouter:使用url的hash值实现
4)BrowserRouter(推荐使用这种模式):使用H5的的history API实现
5)Link组件:用于指定导航连接(a标签):Link被编译成a,在BrowserRouter中,to相当于location.pathname
6) Route组件:指定路由展示组件相关信息,path路由规则,component:展示的组件
3、路由的执行过程
1)点击Link组件(a标签),修改浏览器地址栏中的url
2)React路由监听到地址栏url的变化
3)React路由内部遍历所有的Route组件,使用路由规则(path)与pathname比较
4)当路由规则path能够匹配地址栏中的pathname,则展示该Route组件内容
4、编程式导航
编程式导航:通过js代码实现页面跳转
this.props.history.push('/home')
history是React路由提供的,用于获取浏览器历史记录相关信息
1)push(path):跳转到某个页面,path表示跳转路径
2)go(n):前进或后退到某个页面,(-1后退到上一页面,1前进到下个页面)
5、默认路由
默认路由:表示进入到页面时就会匹配的路由
1)默认路由path为:/
<Route path="/" component={Home}></Route>
6、匹配模式
1)模糊匹配模式
问题:当Link组件的to属性值为"/login",默认路由也会匹配上
原因:默认情况下React路由是模糊匹配模式
模糊匹配规则:只要pathname以path开头就会匹配成功
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
const Home = () => (<p>默认页面</p>)
const Login = () => (<p>登录页面</p>)
const App = () => {
<Router>
<div className="app">
{/* 点击这里,会将Home Login都渲染 */}
<Link to="/login">登录页面</Link>
{/* 默认路由 */}
<Route path="/" component={Home}/>
<Route path="/login" component={Login}></Route>
</div>
</Router>
}
2)精确匹配
定义:给Route组件添加属性exact属性,就会变成精确匹配
精确匹配:当path和pathname完全匹配才会展示该路由
{/* 默认路由 精确匹配*/}
<Route exact path="/" component={Home}/>
给默认路由添加exact属性
路由基础总结
1)React路由可以有效管理多个视图(组件),实现SPA
2)Router组件包裹整个应用,只用一次
3)Link组件是入口,Route组件是出口
4)通过props.history实现编程式导航
5)默认模糊匹配,添加exact变精确匹配
6)React路由的一切都是组件