4

mindnote

前情提要

我学习和使用Vue大概有一年时间了,但是最近才开始学习的React,在没使用过React之前就经常看到许多博主都在将两者进行对比,在实践完以后,我想站在我自己的角度看看。

那就开始了

官方文档

Vue官方文档
React官方文档【中文版】

  • 个人感觉Vue的文档划分的更加好一点,会把许多概念都讲的比较清晰(虽然第一次看的时候啥都没看懂)同时把一些相关的生态系统也归纳到了一起,例如vue-cli、vue-router、vuex等,比较方便
  • React的文档感觉比较注重实操,对基础的讲解较少,在教程部分就会教你如何实现一个井字棋的(这一点是比较友好的)

组件

这两个框架都是推荐把页面组件化的,但是两者之间对于组件也有各自的不同

生命周期

Vue
  • 主要分为8个阶段:
    beforeCreate
    created (在这个阶段就可以首次拿到data中定义的数据)
    beforeMount
    mounted(在这个阶段Dom树渲染完毕可访问Dom结构)
    beforeUpdate
    updated
    beforeDestroy
    destroyed

vue生命周期

React
  • 主要分为3个阶段:
    Mounting初始化 -> Updating运行中 -> Unmounting销毁

React生命周期

  • 生命周期中的方法

    • 【react 16.0之后已移除】 componentWillMount():在render()之前执行,所以在这个阶段的setState()不会重新渲染;通常用constructor()代替
    • render():在componentWillMount()之后执行
    • componentDidMount():在render()之后执行,所以在这个阶段的setState()会重新渲染;这里可以对DOM进行操作
    • 【react 16.0之后已移除】 componentWillReceiveProps(nextProps):当已挂载组件收到新的props时执行,但有可能props传入时没有发生改变但仍然重新渲染了,如果想要避免这种情况可以在传入新的props时比较一下新旧props之间是否发生变化;这里需要注意一下,如果只是调用了setState()的话是不会触发这个方法的,只有props发生改变或者没有发生改变时才会触发这个方法
    • shouldComponentUpdate(nextProps,nextState):在接收到新的props或者state时确定是否发生重新渲染,默认值为true;在首次渲染时不会触发这个方法
    • 【react 16.0之后已移除】 componentWillUpdate(nextProps,nextState):在shouldComponentUpdate()之后,render()之前触发;在组件初始化时不会被触发
    • componentDidUpdate(prevProps,prevState):在componentWillUpdate(nextProps,nextState)之后调用;在组件初始化时不会被触发,此时可以对DOM进行操作

组件形式

Vue Template
  • Vue组件的编写结构分为三部分,分别是 template(HTML) script(JS) style(CSS)
  • 将三者独立开来,更好的注重每一部分的开发
  • CSS:Vue默认是在单文件组件中在<script scoped></script>标签里写CSS样式,我们可以通过在<script scoped></script>标签中写上scoped,这样这部分样式就只用来控制该组件的样式,而不会影响到其他组件。
  • JS:模版部分使用数据:需要将变量放在双大括号内{{}}

    <template>
      <!-- HTML Code -->
      <div>{{name}}</div> 
    </template>
    
    <script>
      export default{
        name: 'NewComponent',
        data() {
          return {
            name: 'xx'
          }
        }
      }
    </script>
    
    <style scoped>
      /* CSS Code */
    </style>
React JSX
- React支持Class组件和Function组件
  • React组件使用render渲染函数,可以用JavaScript来构建视图页面,常包含了大量的逻辑
  • CSS:React是通过使用className字段来设置样式,一般都是引入外部的css,且一般都会使用less预编译
  • JS:将变量放在{}

    // class组件
    class Template extends React.Component{
       render() {
          return (
            <div className="shopping-list">
              <h1>Shopping List for {this.props.name}</h1>
            </div>
          );
       }
    }
    // function组件
    function NewComponent() {
      const [name, setName] = useState('');
      return (<div>{name}</div>);
    }

数据管理

Vue对象属性
  • 数据由data属性在对象中进行管理,可以直接改变

    export default {
       name: 'app',
       data() {
          return {
            orders: {}
          }
       }
    }
React状态管理
class组件state
  • 数据通过state保存状态,需要通过setState来改变
  • setState更新的是组件的部分数据,react会自动将数据合并
  • setState原理:你真的理解setState吗

    state = {
      version: Version.V3
    };
    
    handleVersionChange(version: Version) {
      this.setState({ version: Number(version)}
    );
function组件hooks
  • 数据需要通过setXXX来改变
  • useState 不会自动合并更新对象

    function Counter({initialCount}) {  
      const [count, setCount] = useState(initialCount);  
      return (    
          <>      
              <button onClick={() => setCount(initialCount)}>Reset</button>      
          </>  
      ); 
    }

数据流

单向数据流中的单向:我理解的是父级数据的更新会向下流动到子组件中,但是反过来则不行,这样可以防止从子组件意外改变父级组件的状态

数据流

Vue双向数据绑定

vue仍然是单向数据流
表现形式
  • 使用v-model
  • 一般有两种使用情景:

    • 组件
    • input元素
  • v-model实质为语法糖
<input v-model="message" />

// 等价于:
<input 
   v-bind:value="message" // 与data中声明的数据进行绑定
   v-on:input="message=$event.target.value" // 监听输入框中值的变化
/>

// 实现原理
// 修改AST元素,给el添加一个prop,相当于动态绑定了value
addProp(el,'value',`(${value})`);
// 添加事件处理,相当于给input绑定了input事件
addHandler(el,event,code,null,true);
实现原理
  • vue使用的是发布者订阅者的模式+数据劫持的方式来实现的,在组件中我们定义data时,vue会遍历这个对象,通过Object.defineProperty()给每一个值都添加gettersetter方法,然后每一个组件都有一个watcher来监听数据的变化,当数据发生变化的时候,即触发setter时,就会发布消息给订阅者,触发相应的监听回调
Vue2.0的缺陷
  • 不具备监听数组的能力,需要重新定义数组的原型来达到响应式
  • 无法检测到对象属性的添加和删除
  • 只能劫持对象的属性(假如需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历,显然能劫持一个完整的对象是更好的选择)
解决方法:Vue.set() || this.$set()
  • 如果在实例创建之后添加新的属性到实例上,它不会触发视图更新,因为此时添加的属性并没有绑定上gettersetter,因此这个属性是非响应式。如果我们想要把这个属性变成响应式的话,可以通过Vue.set()或者this.$set()这两种方式添加新的属性
  • 除了添加新的属性以外,改变数组的一些属性也不会使得视图更新,
  • 利用索引直接设置数组的某一项 arr[1] = 10
  • 直接修改数组的大小 arr.length = 10
  • 对于数组除了可以通过Vue.set()this.$set()这两种方式,还可以使用数组的一些API来触发更新,如splice() concat()等会修改原始数组的API
Vue3.0的改进
  • 使用ES6中的proxy

    • 可以劫持到整个对象而非属性,并返回一个新的对象
    • 可以监听到数组的变化

React单向数据流

特点
  • React采用单向数据流的形式,即它只接收数据,但不改变数据,只监听数据的改变;当数据发生变化的时候,它会接收使用新的数据,重新进行渲染。
  • 我觉得单向数据流最大的好处的话,是当多个组件都要对同一个值进行操作的时候,由于数据只有一份,因此能够保持它的一致性。

状态管理器

什么情况下我们要使用状态管理器呢?
一般是当多个组件需要共同维护一些数据,使用传值的方式会十分复杂,因而我们可以把这些需要共同维护的数据提取出来,放在store中共同维护,这样就可以保证数据的一致性

Vue

Vuex
  • 单一数据源:只有一个store
  • mutation(同步操作):修改state只能通过mutation的方式,需要通过store.commit()来提交mutation
  • action(异步操作):action里面可以包含多个mutation,最后也是要通过store.commit()来触发mutation,action需要通过store.dispatch()来触发
  • model:引入来模块化,就是想要把store进行拆分,每个 Module 有自己的 state、mutation、action、getter,可以各自维护,最后再把每个store组合起来,不违背Vuex的单一数据源

React

Redux
  • 单一数据源:只有一个store
  • state是只读的:需要通过reducer纯函数返回一个新的state
  • 单向数据流
  • 使用的是不可变数据,每次更新都是使用新的state来替换旧的state
Mobx-React
  • 可以有多个store
  • store中的state可以直接修改
@observable // 我们要在需要观察的数据加上@observable
current: number = 1;
total: number = 0;

@action // 将修改被观测变量的行为放在action中
updateCurrent(current: number) {
    this.current = current;
}

// 对于异步操作,action无法影响当前函数调用的异步操作,可以使用runInAction来解决
async getList() {
  // some code
    runInAction(() => {
      this.total = res.total;
  });
}

路由

Vue-Router

vue是单页面应用,页面跳转不会发送请求
hash模式
  • 简单点说就是URL后带有#标志的就是hash路由

    // 像这样
    http://localhost:8080/home#heading
表层原理
  • 使用hash来模拟一个完整的URL,所以当URL发生改变的时候,不会重新加载
  • hash出现在URL中,但并不会包含到http请求中,因此当hash值发生变化的时候,并不会引起页面的请求
  • 当#后的值发生变化的时候,会向浏览器的历史浏览增加一个记录,当点击后退按钮时,会弹出,以此来实现页面的跳转
  • 通过onhashchange事件监听hash值的变化
history模式
  • URL后不带有#标志的
// 像这样
http://localhost:8080/home/center
表层原理
  • history模式主要使用的是HTML5中提供的APIhistory.pushState()history.replaceState()来实现
  • 需要注意的是,history模式不怕前进,不怕后退,就怕刷新
  • history模式下如果刷新页面的话,可能会返回404,因为当刷新页面的时候,会真实的向服务端发送请求,但如果此时该页面没有在服务端配置过的话就会返回404,因此需要服务端进行重定向,可以使用Nginx,使用try_file和rewrite实现重定向

React-Router(待完善)

BrowserRouter
  • 与Vue-Router中的history模式类似
HashRouter
  • 与Vue-Router中的hash模式类似

脚手架(待补充)

Vue-Cli

Create-React-App

单元测试(待补充)

从Vue到React

  • 虽然我是先学习和使用Vue的,但是由于以前学习过Java等一些面向对象的语言,所以从Vue到React的过渡并没有不适应,反而觉得很熟悉;而且React使用JS来构建页面,可以在里面写逻辑,我觉得非常安逸呀。
  • 但其实不管是哪一种框架,适合这个项目的框架那它就是好框架,不同的框架有不同的特殊点,如果这个特殊点和项目的要求想契合的话,那就是它了!

Ong_
23 声望0 粉丝

前端入坑者