React

180 阅读5分钟

1.虚拟DOM

虚拟DOM 本质上是JS对象,通过createElement创建DOM节点,包含 type,props,children三个参数,然后由render将虚拟DOM渲染为真实DOM,再appendChild将DOM节点添加到页面上。在元素发生改变时更新JSX,通过diff算法记录元素更新的差异,相比直接操作真实DOM节约损耗。

diff算法:深度遍历元素节点,对比preState和newState,将差异记录到一个对象中,最后只更新有差异的节点。

虚拟DOM是为了优化浏览器性能,假如一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是先把这10次的diff内容保存到一个JS对象中,最后再统一更新DOM树,避免了多次反复操作DOM,提升了浏览器性能。

2.JSX

  • HTML 模板嵌入到JS代码中,写在js中的html,是一个React特有的语法糖
  • 需要被babel编译成js对象,这个对象就是虚拟DOM,更加方便动态更新元素,遵循javascript所有语法。

3.SetState

React中必须通过setState改变元素状态,引发页面重新渲染。
React中由于性能考虑,将多次setState的调用合并为一次,将每一次状态的改变记录到一个队列中,差不多的时候引发一次生命周期更新。因此有时候表现的像异步。

当setState参数为对象和函数时的区别
为对象时无法立刻得到最新的值

    this.setState({ index: this.state.index + 1 }, () => {
      console.log(this.state.index);
    })
    this.setState({ index: this.state.index + 1 }, () => {
      console.log(this.state.index);
    })
  }
  // 1
  // 1

为函数时,接收两个参数(state,props)返回state更新之后的一个对象,此时更新状态不依赖this.state,而是依赖参数state,接收最新的参数,表现为同步。

  componentDidMount() {
    this.setState((preState) => ({ index: preState.index + 1 }), () => {
      console.log(this.state.index);
    })
    this.setState(preState => ({ index: preState.index + 1 }), () => {
      console.log(this.state.index);
    })
  }
   // 2
   // 2

总结 :

  • setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
  • setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
  • setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

4.组件通信

  • 父组件——>子组件:父组件通过属性将变量或方法传递给子组件,子组件通过props接收
  • 子组件——>父组件:子组件接收父组件传过来的方法,子组件中调用父组件的方法,将数据以参数的方式传递给父组件,这样父组件方法就得到回调了,也收到数据了。
  • 兄弟组件:通过共有的父组件

eg.组件 A 中的表单 value 值,告知了父级 Container 组件(通过 setValue函数改变state),组件 B 依赖于 Container 传下来的 state,会做出同步更新。这里的中间者是 Container。

  • 跨级组件通信:context(上下文)将要传递的值放在一个公共容器中provider,里面的所有组件都可以获取公共的值,污染全局环境。
  • 发布订阅:event.proxy.trigger 发布消息 event.proxy.on监听并接收消息。
  • 统一状态管理工具:redux

5.Redux

6.React Hooks

  • useState
  • useEffect
  • useContext
  • useReducer
  • useRef
  • useMemo
  • useCallback
    Hooks有哪些优势,解决哪些以前的缺陷

7.React生命周期

旧的生命周期: 更新后生命周期:

  • 生命周期更新是为了解决什么问题
  • 如果要在每次渲染时请求接口获取数据,应该把它放在哪个生命周期里执行

8.React中key值作用

key作为组件的唯一标识符,类似身份证,react通过key值来识别组件。key值可减少不必要的diff算法,在diff算法中比较同级节点,根据key值来匹配组件,先遍历新的虚拟dom结构,对比前后的key值,若key值存在则不销毁组件,检查属性是否发生改变,不改变则不更新组件,发生改变则记录属性的变化,最后更新组件。key值不同则销毁组件,重建。 (减少重绘,复用节点)

9.类组件和函数组件

函数组件:无状态,没有state,生命周期,只接收一个props值

10.Refs

Refs 是一个获取DOM节点或react元素实例的工具,通过createRef,将其传递给DOM元素后,通过ref的current属性可获取DOM节点再执行后续操作

function Example () {
    // inputEl这个变量是useRef函数的返回值,那么这个变量给谁当ref属性,就能表示在哪里
    const inputEl = useRef(null)

    const onButtonClick = () => {
        inputEl.current.value = '猛哥贼拉帅'
        console.log(inputEl)
    }
    return (
        <>
        <input ref={inputEl} type="text"/>
        <button onClick={onButtonClick}>在Input上展示文字</button>
        </>
    )
}
export default Example

11.为什么选择框架(React 优点)

12.高阶函数HOC/ 高阶组件

将函数或组件作为参数或返回值
具体应用:

  • react-redux 中的 connect,将state和 action 方法 映射到被包裹组件的propss上
  • react-router 中 的withRouter,将路由(location,router)相关加到props中

13.pureComponent(纯组件、纯函数)

正常情况下,父组件每次有state或者props改变,子组件都会重新渲染。但是如果我们在shouldComponentUpdate阶段判断新旧属性和状态是否相等,是否需要重新渲染子组件。减少render()方法的触发,节省了在虚拟DOM生成与对比的过程,性能得到提升。

和component相比,pureComponent会有一个浅比较的过程,比较前后props和state是否发生变化,不过这一比较是浅比较,基本数据类型比较值,引用数据类型比较引用是否变化,这样一来,如果同一个对象的属性发生变化则无法检测到就不会相应更新渲染。