React的通信方式
- 父子组件:props
- 兄弟组件(非嵌套组件):消息订阅-发布(pubs-sub)、redux集中式管理
- 祖孙组件(跨级组件):消息订阅-发布(pubs-sub)、redux集中式管理、conText(生产者-消费者模式)
react生命周期函数
- 旧的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yanvjM61-1661950530564)(%E9%9D%A2%E8%AF%95%E5%87%86%E5%A4%87%2064d3ed4453ae44a38f71e8b99d75fcc4/Untitled.png)]
- 新的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FaR8g2KC-1661950530565)(%E9%9D%A2%E8%AF%95%E5%87%86%E5%A4%87%2064d3ed4453ae44a38f71e8b99d75fcc4/Untitled%201.png)]
- 挂载阶段:
- constructor: 构造函数,最先被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this
- getDerivedStateFromProps: static getDerivedStateFromProps(nextProps, prevState),这是个静态方法,当我们接收到新的属性想去修改我们state,可以使用getDerivedStateFromProps
- render: render函数是纯函数,只返回需要渲染的东西,不应该包含其它的业务逻辑,可以返回原生的DOM、React组件、Fragment、Portals、字符串和数字、Boolean和null等内容
- componentDidMount: 组件装载之后调用,此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnMount中取消订阅
- 更新阶段:
- getDerivedStateFromProps: 此方法在更新个挂载阶段都可能会调用
- shouldComponentUpdate: shouldComponentUpdate(nextProps, nextState),有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此生命周期来优化React程序性能
- render: 更新阶段也会触发此生命周期
- getSnapshotBeforeUpdate: getSnapshotBeforeUpdate(prevProps, prevState),这个方法在render之后,componentDidUpdate之前调用,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用
- componentDidUpdate: componentDidUpdate(prevProps, prevState, snapshot),该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要用到 DOM 元素的状态,则将对比或计算的过程迁移至 getSnapshotBeforeUpdate,然后在 componentDidUpdate 中统一触发回调或更新状态。
- 卸载阶段:
- componentWillUnmount: 当我们的组件被卸载或者销毁了就会调用,我们可以在这个函数里去清除一些定时器,取消网络请求,清理无效的DOM元素等垃圾清理工作
前端路由
- 前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的。在 Web 前端单页应用 SPA(Single Page Application)中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。
两种方式实现前端路由
- hash
- hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新
- 通过
hashchange
事件监听 URL 的变化。改变 URL 的方式只有这几种:- 通过浏览器前进后退改变 URL
- 通过标签改变 URL
- 通过window.location改变URL
- 这几种情况改变 URL 都会触发
hashchange
事件
- history
- history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
- history 提供
popstate
事件,但 popstate 事件有些不同:- 通过浏览器前进后退改变 URL 时会触发
popstate
事件, - 通过pushState/replaceState或标签改变 URL 不会触发
popstate
事件。
- 通过浏览器前进后退改变 URL 时会触发
- 好在我们可以拦截 pushState/replaceState的调用和标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
vue router 前端路由
- 基础语法
//index.js配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../component/Home'
//1.通过Vue.use(插件),安装插件
Vue.use(VueRouter)
//2.创建VueRouter对象
const router = new VueRouter({
routes,
mode: 'history' //默认是hash模式,这样设置后会设置成history模式
})
const routes = [
{
path: '/',
redirect: '/home'
},
{
path:'/home',
component: Home
}
]
//3.将router对象传入到Vue实例
export default router
--------------------------------------------------------------
//App.vue文件中挂载
<router-link to="/home">首页</router-link> //会被渲染成a标签
<router-view></router-view> //占位
-
通过代码修改路由
this.$router.push('/home')
this.$router.replace('/home')
-
路由懒加载
const Home = () => import('../components/Home')
-
导航守卫
router/index.js
//找到router对象
router.beforeEach((to, from, next)=> {
//从from跳转到to
document.title = to.matched[0].meta.title
next()
})
//路由配置需添加meta属性
{
path: '/profile',
component: Profile,
meta: {
title: '档案'
}
}
- meta:元数据,描述数据的数据
- 前置守卫
router.beforeEach()
跳转前调用 - 后置钩子
router.afterEach()
跳转之后调用router.afterEach((to, from) => {})
- 上面两个守卫都是全局守卫
- 路由独享的守卫
- 组件内的守卫
插槽slot
- Slot 是组件内部的占位符,用户可以使用自己的标记来填充。
- 插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
- slot就是一个空壳子,它显示与否以及怎么显示完全是由父组件来控制。不过,插槽显示的位置由子组件自身决定,
slot
写在组件template
的哪块,父组件传过来的模板将来就显示在哪块。
diff算法 虚拟dom
虚拟dom
- 虚拟 DOM 本质就是用一个原生的 JavaScript 对象去描述一个 DOM 节点,是对真实 DOM 的一层抽象。虚拟 DOM 对象最基本的三个属性:标签类型、标签元素的属性、标签元素的子节点。
- 由于在浏览器中操作 DOM 是很昂贵的:用原生 JS 或者 jQuery 操作 DOM 时,浏览器会从构建 DOM 树开始从头到尾执行一遍流程。频繁地操作 DOM,会产生一定的性能问题,因此需要尽可能地一次性将差异更新到 DOM 中,这样保证了 DOM 不会出现性能很差的情况。
- 但是这样并不能解决问题,所有就有了虚拟 DOM。
diff算法
- Diff 算法的核心就是对虚拟 DOM 节点进行深度优先遍历,并对每一个虚拟节点进行编号,在遍历的过程中对同一个层级的节点进行比较,最终得到比较后的差异。在比较差异时只会对同一层级的节点进行比较,采用同层比较。
- Diff 的实现,最粗暴的方法就是遍历每个新虚拟 DOM 节点,和旧虚拟 DOM 节点比对。在旧 DOM 中是否存在,不同就卸载原来的上新的。若存在只是属性或者属性值变了。直接 Props,更新节点。