zhangli20080808 / mini-react

react simple version and 18 learning

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

react 18

官方更新博客

新的理念

并发渲染

Concurrent - 并发性,并不是一个新的特性,而是 react 内部衍生出来的一种新的工作机制。并发渲染机制 - Concurrent rendering。在 Concurrent 模式中,渲染不是阻塞的,它是可中断的。

更新优先级

  1. 在并发模式之前,更新是没有优先级的说法。优先级高的更新并不能打断优先级低的更新,需要等前面的更新完成才能进行
  2. 用户对不同的操作对交互的执行速度也有不同的预期。比如
  • 高优先级的操作 - 用户输入,窗口缩放和拖拽事件
  • 低优先级 - 数据请求,文件下载
  1. 高的会中断低优先级的更新
  2. 等高优先级更新完后,低优先级基于高优先级更新的结果重新更新
  3. 对于向创建新的 dom 节点和运行组织中的代码,是可以中断已经开始的渲染。

双缓冲

新的特性

  1. 新的渲染 - Api createRoot
  2. 自动批处理 - Automatic Batching,特殊的优化机制
  3. 过渡 Api - Transitions
  4. Suspense Api

start

yarn create vite zl-mini-react --template react
cd zl-mini-react
yarn
yarn dev

createRoot

// 在特定的dom节点上,创建一个root对象
const root = createRoot(document.getElementById('root'));
// 使用 root 的render方法来渲染对应的组件或者卸载组件
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// root.unmount()
// ReactDOM.unmountComponentAtNode(root) 之前调用方法会卸载该容器中的渲染

// vue3
const app = createApp();
app.mount('#app');
app.unmount('#app');

自动批处理

其实很好理解,在 react 中可以减少 re-render 的次数

const [count, setCount] = useState(0);
const [show, setShow] = useState(true);
console.log('update', show, count);
const batchUpdate = () => {
  setCount(count + 1);
  setShow(!show);
};
useEffect(() => {
  setTimeout(() => {
    batchUpdate();
  }, 2000);
}, []);
// 在react 18中,自動批處理會合併更新,只會render一次
// update true 0
// update false 1
// 在17中,會render兩次
// update true 0
// update false 0
// update fasle 1

虚拟 dom 概念复习

what

⽤ JavaScript 对象表示 DOM 信息和结构,当状态变更的时候,重新渲染这个 JavaScript 的对象结构。这个 JavaScript 对象称为 virtual dom。

虚拟 DOM(Virtual DOM)是对 DOM 的 JS 抽象表示,它们是 JS 对象,能够描述 DOM 结构和关系。应用 的各种状态变化会作用于虚拟 DOM,最终映射到 DOM 上。

why?

DOM 操作很慢,轻微的操作都可能导致⻚⾯重新排 版,⾮常耗性能。相对于 DOM 对象,js 对象处理起来更快, ⽽且更简单。通过 diff 算法对⽐新旧 vdom 之间的差异,可以 批量的、最⼩化的执⾏ dom 操作,从⽽提⾼性能。

where?

react 中⽤ JSX 语法描述视图,通过 babel-loader 转译 后它们变为 React.createElement(...)形式,该函数将⽣成 vdom 来描述真实 dom。将来如果状态变化,vdom 将作出相 应变化,再通过 diff 算法对⽐新⽼ vdom 区别从⽽做出最终 dom 操作。

对比两个虚拟 dom 树一般也就三种操作

  • 删除、替换、更新

fiber 概念复习

fiber 本质上还是 vdom,只不过基础结构上发生了变化

why?

对于⼤型项⽬,组件树 会很⼤,这个时候递归遍历的 成本就会很⾼,会造成主线程被持续占⽤,结果就是 主线程上的布局、动画等周期性任务就⽆法⽴即得到 处理,造成视觉上的卡顿,影响⽤户体验。

组件类型

  • 文本节点
  • Html 标签节点
  • 函数组件
  • 类组件
const jsx = (
  <div className='box border'>
    <h1>omg</h1>
    <h2>ooo</h2>
    <FunctionComponent name='函数组件' />
    <ClassComponent name='class组件' />
  </div>
);
const jsxfiberNode = {
  child: {
    stateNode: 'div.box.border',
    tag: 5, // 原生标签 HostComponent
    child: {
      // 第一个子节点,此处是h1,之前传统的子节点都是存储在数组中
      // 如果后面还有节点,就通过 sibling
      stateNode: 'h1',
      tag: 5,
      sibling: {
        stateNode: 'h2',
        tag: 5,
        // 还有兄弟 函数组件
        sibling: {
          stateNode: null, // 函数组件本身没有dom节点
          tag: 0,
          sibling: {
            stateNode: 'ClassComponent', // 指向类组件的实力
            tag: 1,
            sibling: null, // 没有兄弟节点啦
            return: {
              // 父节点
              stateNode: 'div.box.border',
              tag: 5,
            },
          },
        },
      },
    },
  },
};
function createFiber(vnode, returnFiber) {
  const fiber = {
    type: vnode.type,
    key: vnode.key, // 常规key值
    props: vnode.props,
    stateNode: null, // 原生标签,指dom节点,类组件的时候,指向实例
    child: null, // 第一个子 fiber,也就是第一个子节点
    sibling: null, // 下一个兄弟fiber
    return: null, // 父fiber
    flags: null, // 标记是什么类型的,比如后续 插入,末尾移动等,标记
    alternate: null, // 老节点
    deletions: null, // 要删除子节点,null或者[]
    index: null, // 当前层级下的下标,从0开始,即 在当前层级下是第几个子节点,记录位置。主要是为了,比如上次更新在某个位置,下次更新在什么地方,位置有没有发生变化,需不需要移动,都是根据index来判断

    memoizedProps: {}, // 更新到组件上的值,
  };
  return fiber;
}

About

react simple version and 18 learning


Languages

Language:CSS 46.6%Language:JavaScript 44.0%Language:HTML 9.4%