美文网首页
react/vue常见问题整理

react/vue常见问题整理

作者: _咻咻咻咻咻 | 来源:发表于2021-02-24 10:05 被阅读0次

    一、react

    1. react生命周期

    react 15生命周期.png react 16生命周期.png

    react 16生命周期相对于15的变化:
    componentWillMount,componentWillReceiveProps, componentWillUpdate准备废除。理由:主要是16 版本 render 之前的生命周期可能会被多次执行。
    static getDerivedStateFromProps和 getSnapshotBeforeUpdate新增,用于补充上述的生命周期。

    2. 对虚拟dom的理解

    本质上是 JavaScript 对象,这个对象就是更加轻量级的对 DOM 的描述。DOM 有很多属性,如果把对 DOM 的 diff 操作转移到 JS 对象,就可以避免大量对 DOM 的查询操作。这个更轻量级的 JS 对象就称为 Virtual DOM 。

    虚拟dom工作过程:

    1. 维护一个使用 JS 对象表示的 Virtual DOM,与真实 DOM 一一对应
    2. 对前后两个 Virtual DOM 做 diff ,生成变更(Mutation)
    3. 把变更应用于真实 DOM,生成最新的真实 DOM

    可以看出,因为要把变更应用到真实 DOM 上,所以还是避免不了要直接操作 DOM ,但是 React 的 diff 算法会把 DOM 改动次数降到最低。
    diff的原理:将树形结构按照层级分解,只比较同级元素;给列表结构每一个单元添加key属性,方便比较。

    3. setState

    如果直接修改state,react无法得知需要重新渲染组件,使用setState(),react可以更新组件UI。调用setState后,react将传入的参数与当前状态合并,生成新的元素树,与老的元素树进行对比,根据差异对界面进行最小化重新渲染。
    State 的更新可能是异步的,所以如果setState需要要依赖this.state或this.props的值,需传入函数。
    出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用(render)。setState不会立即改变state的值,在 React的生命周期和合成事件中, React仍然处于他的更新机制中,这时无论调用多少次 setState,都不会立即执行更新,而是将其放入一个任务队列。当上一次更新机制执行完毕(eg;生命周期),将多个setState合并,一次性渲染页面。
    通过 addEventListener || setTimeout/setInterval 的方式处理的setState会同步更新。

    4. react的事件机制

    react事件没有绑定在真实的dom上,而是通过事件代理,绑在document上,对事件进行分发。React的所有事件都通过 document进行统一分发。当真实 Dom触发事件后冒泡到 document后才会对 React事件进行处理。
    react事件要自己绑定this,因为事件绑定在document上,不是真实要调用的组件上。
    react事件和原生事件区别:

    1. react事件命名为驼峰式,不是全小写;
    2. jsx可以传递一个函数为事件处理程序,不是字符串
    3. react中不能返回false阻止默认事件,必须调用preventDefault。

    合成事件:事件处理函数的参数。事件处理程序将传递 SyntheticEvent 的实例,这是一个跨浏览器原生事件包装器。它具有与浏览器原生事件相同的接口。
    因为真实dom出发时间冒泡到document后才会处理react事件,所以事件触发顺序为:原生事件 =》 合成事件 =》react真正在document上挂载的事件

    react事件和原生事件最好不要混用。因为原生事件如果执行了stopPropagation方法,所有元素的事件都无法冒泡到document上,所有的react事件都无法触发。

    5. refs

    Refs是react提供的用来访问dom或者组件的句柄。是父组件用来获取子组件的dom元素的。我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回。

    1. ref设置为普通字符串
      <button ref="myBtn"></button>
      给元素/组件定义ref属性,后续可以通过 this.refs.myBtn 来获取这个真实DOM对象/组件的实例对象
    2. ref设置为回调函数
      <button ref={(sl)=> { this.myBtn = sl } }></button>
      给元素/组件定义ref属性,后续可以通过 this.myBtn 来获取这个真实DOM对象/组件的实例对象
    • refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值。
    function CustomForm ({handleSubmit}) {
      let inputElement
      return (
        <form onSubmit={() => handleSubmit(inputElement.value)}>
          <input
            type='text'
            ref={(input) => inputElement = input} />
          <button type='submit'>Submit</button>
        </form>
      )
    }
    

    6. 动态加载

    const LazyComponent = React.lazy(() =>
      import(/* webpackChunkName: 'lazyComponent'*/ "../components/LazyComponent")
    );
    

    7. Hook

    hook之前的函数组件是无状态、无副作用,只作单纯的展示组件。
    Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。
    用法: useState, useEffect,useReducer,自定义hook

    import React, { useState, useEffect } from 'react';
    
    function FriendStatus(props) {
      //定义一个state:isOnline,和修改state的方法setIsOnline
      const [isOnline, setIsOnline] = useState(null);
    
      function handleStatusChange(status) {
        setIsOnline(status.isOnline);
      }
      //副作用,相当于 componentDidMount 和 componentDidUpdate,页面每次渲染都会执行
      useEffect(() => {
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        //return一个方法就是清楚副作用,相当于componentWillUnmount
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });
      //useEffect也可以传入第二个参数[isOnline],代表只有isOnline修改时才执行副作用
      //若第二个参数为 [],代表只有页面第一次渲染执行副作用
    
      if (isOnline === null) {
        return 'Loading...';
      }
      return isOnline ? 'Online' : 'Offline';
    }
    

    8. 受控组件和非受控组件

    受控组件:使用表单元素时,将react的state作为数据的唯一源,并且控制着用户输入时表单发生的操作。被react以这种方式控制取值的表单元素就是受控组件。
    非受控组件:表单数据由dom节点处理。

    //受控组件
    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ''};
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
      handleChange(event) {
        this.setState({value: event.target.value});
      }
      handleSubmit(event) {
        alert('提交的名字: ' + this.state.value);
        event.preventDefault();
      }
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              名字:
              <input type="text" value={this.state.value} onChange={this.handleChange} />
            </label>
            <input type="submit" value="提交" />
          </form>
        );
      }
    }
    
    //非受控组件
    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.input = React.createRef();
      }
      handleSubmit(event) {
        alert('A name was submitted: ' + this.input.current.value);
        event.preventDefault();
      }
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Name:
              <input type="text" ref={this.input} />
            </label>
            <input type="submit" value="Submit" />
          </form>
        );
      }
    }
    

    9. 高阶组件(HOC)

    高阶组件(HOC)是参数为组件,返回值为新组件的函数。

    二、vue

    1. vue2.x的响应式原理

    vue初始化数据时,用Object.defineProperty()将data中的property转为getter/setter。每个vue实例对应一个watcher实例,它在组件渲染过程中将所有property记录为依赖。当属性发生变化时触发依赖项的setter,通知watcher,使对应组件重新渲染。
    Vue3.x改用Proxy替代Object.defineProperty。

    2. vue2.x中如何监测数组变化

    使用函数劫持的方法,对data中的数组进行方法重写,使其能够通知依赖变更,如果数组中包含引用类型,使用递归遍历进行监控。

    3. nextTick

    在下次dom更新后执行回调。nextTick主要使用了宏任务和微任务,根据执行环境尝试采用Promise,MutationObserver,setImmediate和setTimeout。

    4. 生命周期

    beforeCreated, created, beforeMounted, mounted, beforeDestroyed, destroyed

    5. computed 和 watch

    computed是一个计算属性,基于响应式依赖进行缓存,适用于比较消耗性能的计算场景。很长很复杂的表达式放在模板难以维护,就放入计算属性。
    watch是一个侦听器,监听依赖变化来执行一些操作。

    6. v-if 和 v-show

    v-if在条件成立时才会渲染。提升页面初始渲染性能。
    v-show页面渲染时就会同时渲染,只是将display设为none,不展示。提升页面多次切换渲染性能。

    7. 组件中的data为什么是一个函数

    一个组件被多次使用就是创建了多个实例,这些实例用的都是同一个构造函数,如果data是对象,多个实例共享data的引用,数据会互相影响,使用函数可以避免这个问题。

    8. vue模板编译原理

    vue的模板通常被编译成了render函数。会经历以下阶段:

    • AST语法树
    • 优化
    • codegen

    首先解析模板,转化为AST语法树。使用正则表达式解析模板,遇到标签,文本都会有相应的钩子进行处理。
    模板中有很多数据不是响应式的,首次渲染后不会再发生变化。优化过程就是深度遍历AST语法树,将其标记为静态节点,用来跳过对他们的比对。
    将优化后的AST语法树转换为可执行的代码。

    9. key

    key是在使用v-for的列表中为节点添加标识,如果没有key,vue重新渲染会选择就地修改重用相同元素,而使用key则会根据key的变化进行重新排列,移除key不存在的元素。

    10. keep-alive

    keep-alive用于包裹动态组件,在组件变更时将其进行缓存,再次展示时无需重新渲染。

    <!-- 失活的组件将会被缓存!-->
    <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
    </keep-alive>
    

    11. Vue中组件生命周期调用顺序

    组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
    组件的销毁操作是先父后子,销毁完成的顺序是先子后父。

    加载渲染过程
    父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted
    子组件更新过程
    父beforeUpdate->子beforeUpdate->子updated->父updated
    父组件更新过程
    父 beforeUpdate -> 父 updated
    销毁过程
    父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

    三、react vs vue

    相关文章

      网友评论

          本文标题:react/vue常见问题整理

          本文链接:https://www.haomeiwen.com/subject/gtmyxltx.html