author: heyunjiang
time: 2019.3.27
update: 2019.4.2
每当自己对 vue 或 react 有疑惑的时候,则可以来这里查看相关
总结归纳方式:通读 vue 官方文档,每到一个知识点,同 react 官方文档对比来看,待总结完了,再完整看 react 官方文档一编;日后做项目,如果有发现新的特点或者有所项目感悟,也可以总结到这里来
已经总结到:基础 - vue 深入-自定义事件,该 slot ,都用过,目的是完善文档,寻找自己不熟悉的点
目录
1 整体对比
2 vue 特色
2.1 指令
2.2 实例属性
2.3 computed vs watch
3 标准示例
5 项目经验总结
5.1 父子组件数据组织
5.2 表单可编辑状态数据回滚
5.3 使用 v-if 阻止组件渲染与发起 http 请求
5.4 组件抽离原则
基于以上3个问题,我自己分析了 vue, react 两框架,结合自身使用、官方文档、其他同学的经验来看,总结以下几点
当然,要成为优秀的前端工程师,最本质的还是解决复杂问题的能力
归纳
类型 | react | vue |
---|---|---|
1渐进式框架 |
✔ | ✔ |
2虚拟dom |
✔ | ✔ |
2虚拟dom -特点 |
一个根实例 + 树形后代多实例 | 一个根实例 + 树形后代多实例 |
2虚拟dom -更新方式 |
diff新旧虚拟树 | diff 新旧虚拟树 |
3数据流 -响应式数据 |
非响应式数据 | 双向数据邦定 |
3数据流 -props |
单向数据流 | 单向数据流 |
3数据流 -data |
在 constructor 方法内部设置 this.state = {} | data(){return {}} |
3数据流 -数据驱动 |
主动调用 setState 方法,添加到数据更新队列 | 1. 响应式数据:defineProperty、proxy 添加 watcher 给每个组件的 data 对象; 2. 也可以主动 this.hello = ‘world’,数据变动添加到更新队列; 3. this.$set(this.hello, ‘world’, 27) 添加响应式数据,或者更新数组、对象的值,直接更新数组对应下标值、更新对象属性是不能将数据添加到更新队列,界面无法更新; 4. v-model、v-bind.sync 双向邦定标单数据 |
3数据流 -数组更新 |
this.setState() | 支持直接 arr.push() 或者 arr = […arr, newItem] |
4组件 -格式 |
标准 es6 class 对象, .js |
vue 指定格式, .vue |
4组件 -根组件渲染 |
ReactDOM.render(element, document.body) | new Vue({ele, router, template, components}) |
4组件 -实例 |
每个组件都是一个 react 实例 | 每个组件都是一个 vue 实例 |
4组件 -自定义组件命名 |
名称必须大写开头 | 名称可以大写小写开头 |
4组件 -全局注册 |
无 | Vue.component() 一些通用、常用组件可以考虑全局注册,通过 webpack 进行目录性质的全局注册 |
4组件 -局部注册 |
输出 class 对象或定义函数返回元素,export default class Hello extends React.component {} | 输出 object 配置对象或定义函数返回元素,export default {name:’Hello’, data(){return {}}} |
4组件 -jsx-解析 |
React.createElement(component, props, …children) 的语法糖 | render: createElement => createElement(…) |
4组件 -jsx-内容变量 |
{hello} | jsx 同 react 一致,模板: |
4组件 -jsx-属性变量 |
<span title={this.state.title}> |
jsx 同 react 一致,模板:<span v-bind:title="title"> |
4组件 -jsx-属性批量传递 |
{…childPros} | jsx 同 react 一致,模板:v-bind=”childPros” |
4组件 -jsx-属性变量不传值 |
默认为 true | 默认为 true |
4组件 -jsx-动态生成节点 |
jsx array,可以通过 map 或普通函数 return 节点 | jsx 同 react 一致,模板:v-html, v-for |
4组件 -jsx-class绑定 |
className={this.state.helloClass},组件根元素呢? | jsx 同 react 一致,模板:bind 中可以是字符串、数组、对象,用在组件上可以渲染到组件的根元素上 |
4组件 -jsx-style绑定 |
style={styleObject} | jsx 同 react 一致,模板::style=”styleObject”,多个的话支持数组 |
4组件 -jsx-防xss攻击 |
react 会把所有内容在渲染前解析成字符串 | jsx 同 react 一致,模板:vue 会把所有内容在渲染前解析成字符串,但是不会转换v-html 的值,会有 xss 攻击风险 |
4组件 -jsx-隐身元素 |
React.Fragment 或 <></> | jsx 同 react 一致,模板:template |
4组件 -props |
1.大小写不敏感,在模版中可以采用 kebab-case 规则 2.使用 v-bind 批量传递 prop 3.组件 props 默认存在继承特性,即父组件可以增加未在子组件中定义的prop,比如 class,默认是应用在子组件根节点上,可以使用 inheritAttrs: false 禁止继承 |
|
5生命周期 -实例创建前 |
constructor() | beforeCreate() |
5生命周期 -实例创建成功 |
- | created() |
5生命周期 -实例挂载前 |
getDerivedStateFromProps() | beforeMount() |
5生命周期 -实例挂载成功 |
componentDidMount() | mounted() |
5生命周期 -实例更新前 |
getDerivedStateFromProps()、shouldComponentUpdate()、getSnapshotBeforeUpdate() | beforeUpdate() |
5生命周期 -实例更新成功 |
componentDidUpdate() | updated() |
5生命周期 -实例停用时 |
- | deactivated(),在 keep-alive 组件停用时调用 |
5生命周期 -实例激活时 |
- | activated(),在 keep-alive 组件激活时调用 |
5生命周期 -实例销毁前 |
componentWillUnmount() | beforeDestroy() |
5生命周期 -实例销毁成功 |
componentDidUnmount() | destroyed() |
5生命周期 -实例错误处理 |
getDerivedStateFromError()、componentDidCatch() | errorCaptured() |
6事件 -邦定 |
onClick=”clickCallback” | v-on:click=”clickCallback” 或 @click=”clickCallback” |
6事件 -兼容性 |
✔ | ✔ |
扩展 -状态管理 |
redux | vuex |
渲染到指定 dom 节点 | ReactDom.createPortal() | vue3 teleport 属性 |
相似点
:href=""
,节点属性插入变量@click=""
,可以自定义事件,在组件内部调用 this.$emit() 触发指令修饰:@click.prevent=””
每一个 vue 组件都是一个实例,这个同 react 一样,但是 react 没有什么实例属性或方法,但是 vue 有
$
开头,比如 $ref
$
开头,比如 $watch()
2者不同的使用场景
watch
监听 props 数据,动态更新 data 内部属性值computed
,当一个状态需要由其他数据决定的时候,包括 props 数据、响应式数据、普通数据,但是 computed 数据本身只能作为普通数据,不能用于响应式数据计算属性 computed 特点:
数据缓存
,当依赖数据变化时才会去更新缓存setter 反响更新其它数据
,本来计算属性是只有 getter,但是可以强行增加 setter,反响操作,更新其他值// react 组件
export default class Filter extends React.Component {
constructor(props) {
super(props)
this.state = {
hello: 'world'
}
}
componentDidMount() {}
updateFunction() {
this.setState({
hello: 'china'
})
}
render(){
return (
<div title="{this.title}">{this.hello}</div>
)
}
}
// vue 组件
<template>
<div></div>
</template>
<script>
export default {
name: 'TaskList',
components: {},
props: {
show: {
type: Boolean,
required: true
}
},
mixins: [],
data () {
return {
hello: 'world',
modalStatus: false
}
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
update() {
this.modalStatus = true
}
}
}
</script>
<style></style>
通常实现一个功能模块,需要将该功能模块拆分成多个模块,模块之间信息通过 props
传递数据与方法
index.vue
:入口文件,作为其他组件的父组件,包含通用状态表单数据更新,应当允许数据回滚,比如数据用户编辑出错,选择取消编辑,则数据应当回滚
数据设计方式:originalInfo
, currentInfo
originalInfo: 保存原有数据,当数据出错时,将 currentInfo 部分数据恢复为 originalInfo 的数据
currentInfo:当前表单双向数据邦定数据,由 originalInfo 而来,当 originalInfo 更新时同步更新
如果在父组件中同时存在多个相同子组件实例,如果默认子组件渲染的话,可能会同时由子组件发起重复的 http 请求获取初始化数据,此刻可以使用 v-if 阻止子组件渲染,减少同时发起的 http 请求
思考:
组件抽离类型
header + leftList + rightContent + footer
,每个模块都单独拆分,公共数据由统一父组件管理文件上传、评论列表
等,需要抽离出来组件抽离原则
type, required, desc
为什么说接口数据缓存很重要?
场景描述:在一个页面内,有几个地方需要使用到相同的数据,比较差点的做法是在每次需要时都去发起 http 请求拿数据,好一点的是将数据缓存起来,在需要拿最新数据的时候再发 http 请求
缓存数据的方式:在每次发请求拿数据前,判断一下是否有缓存