react原理

98 阅读5分钟

React

Fiber

react16.8 架构

react将HTML文档 (转成对象 AST)抽象语法树

function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === 'object' ? child : createTextNode(child)
      ),
    },
  };
}

function createTextNode(text) {
  return {
    type: 'TEXT_ELEMENT',
    props: {
      nodeValue: text,
      children: [],
    },
}

手写 render (转成 dom)

reactDOM.render(<App />, document.getElementById("root"));
function render(vDom, container) {
  let dom;
  if (typeof vDom !== "object") {
    dom = document.createTextNode(vDom);
  } else {
    dom = document.createElement(vDom.type); //<p>111</p>
  }
  if (vDom.props) {
    Object.keys(vDom.props)
      .filter((key) => key != "children")
      .forEach((item) => {
        dom[item] = vDom.props[item];
      });
  } //<p className="test">111</p>

  if (vDom.props && vDom.props.children && vDom.props.children.length) {
    vDom.props.children.forEach((child) => render(child, dom));
  } //<p className="test">111</p>
  container.appendChild(dom);
}

为什么需要 fiber

  1. VDOM=>DOM renderer 渲染器 reconciler diff VDOM => create DOM 同步执行(render)

  2. Fiber 是 React 中用于实现调度和协调的一种新的 reconciler 架构。它是在 React 16 中引入的,旨在解决 React 中长时间运行的任务阻塞主线程的问题,提高应用的性能和响应性。

注意:requestIdleCallback 是浏览器提供的一个 API,它允许开发者在浏览器空闲时间执行任务。但是,它并不是一个可靠的 API,因为浏览器的空闲时间可能会受到很多因素的影响,比如用户的操作、网络状况等。因此,React 团队自己实现了一个调度器,用于更可靠地管理和调度任务。 3. 原因: 控制精细度:React需要比它更高的控制精细度。他基于浏览器的空闲时间进行调度,而React 调度器可以根据组件优先级、更新的紧急程度等信息,更精确地安排渲染工作。 跨浏览器兼容性:React需要一个能够跨各个版本或框架的解决方案,以实现一致的性能体验。

1.同步不可中断执行->异步可中断 3. scheduler 任务的优先级 _UN_SAVE_componentWillMount

Fiber 达到的目的,需要解决两个问题

  1. 新的任务调度,有高优先级任务的时候将浏览器空了再继续执行 2.新的数据结构,可以随时中断,下次进来可接着执行

Fiber 架构

  1. Fiber 架构是一种新的 React 架构,它将渲染过程分解为多个小的任务,并且可以在任务之间进行中断和恢复,从而提高了应用的性能和响应性。

  2. Fiber 架构的核心思想是将渲染过程分解为多个小的任务,每个任务都可以在浏览器空闲时间执行,从而避免了长时间运行的任务阻塞主线程的问题。Fiber 架构还引入了新的数据结构,使得任务可以随时中断和恢复,从而提高了应用的性能和响应性。

<div>
  <p>
    <span></span>
    <text></text>
  </p>
</div>
div->p:child->span:child->sibling->text=>return

image.png

受控组件和非受控组件的理解

  1. 受控组件(推荐使用受控组件实现表单) 受代码控制的组件,组件状态全程响应外部数据 例如:input textarea select
  2. 非受控组件(控制能力比较弱) 不受代码控制的组件,组件状态不响应外部数据,需要手动获取组件状态 例如:input textarea select 通过 ref 获取最新的值

unControl.jpg 应用场景 非受控组件不能实现 实时校验

React 事件机制

React 事件机制的工作原理如下:

  1. 当用户与 React 组件交互时,React 会将事件封装成一个合成事件对象,并将其传递给相应的事件处理函数。
  2. 事件处理函数可以在组件中定义,并在其中执行相应的操作,比如更新组件的状态或调用其他函数。
  3. React 事件机制还支持事件冒泡和事件捕获,允许开发者在组件中定义多个事件处理函数,并在事件发生时执行相应的操作。

执行顺序

  1. 原生事件:子元素 DOM 事件监听
  2. 原生事件:父元素 DOM 事件监听
  3. React 事件:子元素事件监听
  4. React 事件:父元素事件监听
  5. 原生事件: document DOM 事件监听 react 所有的事件挂在到 document 对象上 先触发真实 DOM 事件再触发 react 事件 最后真正执行 document 上挂在的事件 组织事件冒泡 阻止合成事件冒泡 e.stopPropagation() 阻止原生事件冒泡 e.nativeEvent.stopImmediatePropagation() 阻止原生事件冒泡 e.nativeEvent.stopPropagation() 阻止默认行为 e.preventDefault() 合成事件:react 事件 原生事件:真实 DOM 事件 事件合成:react 事件和真实 DOM 事件合成一个事件对象

使用 css 方式

css.jpg

cssDiff.jpg

  1. .module.css 只作用于当前组件
  2. styled-components
  3. css in js
  4. css modules
  5. css in js
  6. less
  7. sass
  8. stylus

真实 DOM 和虚拟 DOM 的区别

真实 DOM 文档对象模型 虚拟 DOM 对真实 DOM 的描述

const vDom = <h1 className="text">hello</h1>;
const root = document.getElementById("root");
ReactDOM.render(vDom, root);
const vDom = React.createElement("h1", { className: "text" }, "hello");

区别

虚拟 Dom 不会重排和重绘,跨平台 真实 Dom 反之

用户权限

后端返回 router list 根据 role 展示不同页面 react-router onEnter

<router patch="/home" component={App} onEnter={(nextState, replace) => {
    const uid=util.getUrlParams(nextState,"uid");
    if(!uid){
        replace("/login");
    }else{

    }
    }  />

动态组件(组件懒加载)

const comp = React.lazy(() => import("./components/xxx"));
function a() {
  return (
    <div>
      <suspense fallback={<div>loading...</div>}>
        <comp />
      </suspense>
    </div>
  );
}

react设计思想

  1. 组件化 开闭原则 封闭:组件内部状态自身维护,只处理内部渲染逻辑 开放:组件通信,不同组件props 单向数据流进行交互
  2. 数据驱动视图 不直接操作 DOM,通过数据驱动视图更新
  3. 虚拟Dom 对真实dom进行映射,更新的时候进行两次进行diff算法比较,增量更新

HOC 高阶组件

function withLogin(WrappedComponentA) {
  return WrappedComponentA;
}

原因 1.抽离重复代码,实现组件复用 2.条件渲染,渲染拦截 3.拦截组件的生命周期

属性代理

1.props

function HOC(WrappedComponentA) {
  const newProps = { type: "HOC" };
  return (props) => <WrappedComponentA {...props} {...newProps} />;
}

2.条件渲染

function HOC(WrappedComponentA) {
  return (props) => (props.isShow ? WrappedComponentA : <p>empty</p>);
}

3.外部逻辑的封装