preact与react的区别_用preact 还需要安装react react-dom 吗 - CSDN
  • 在前端界,React 一定是我们耳熟能详的前端开发框架之一,它的出现可以说是带给了我们全的 Web 开发体验...但是在爱好“造轮子”的前端界,我们会发现一些和 React 有着近乎相同的框架,本文的主人公 Preact 便是其...

    在前端界,React 一定是我们耳熟能详的前端开发框架之一,它的出现可以说是带给了我们全的 Web 开发体验,其中也带来了许多新的概念:JSX、virtual-dom、组件化、合成事件等。当我们想从源码层面去研究它的原理时,由于 React 的源码的庞大和晦涩难懂,这也会变得异常困难。但是在爱好“造轮子”的前端界,我们会发现一些和 React 有着近乎相同的框架,本文的主人公 Preact 便是其中的佼佼者,一直都是 React 的顶级“备胎”。但是它相对简练的代码,使得我们更好的去学习和研究它的原理,本文将从以下几个方面介绍:

    • Preact 是什么?
    • PreactReact 的区别有哪些?
    • Preact 是怎么工作的
      • JSX
      • Virtual Dom
      • PreactVirtual DOM diff算法
    • Preact Hooks 的实现
    • 一个组件的生命周期

    从本文你可以学习到(这些点也是高级前端面试的常见问题):

    • 一个前端框架的基本组成
    • 虚拟 DOM 的实现原理及细节
    • Diff 算法细节
    • Hooks 实现原理及细节
    • 组件生命周期及实现原理

    阅读全文: http://gitbook.cn/gitchat/activity/5dd101add4166663fe0e5884

    您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

    FtooAtPSkEJwnW-9xkCLqSTRpBKX

    展开全文
  • PreactReact的轻量级实现,是React比较好的替代者之一,有着体积小的优点,当然与React之间一定会存在实现上的差异,本文介绍了在 setState 方面的差异之处。 源码分析 首先来分析下React以及Preact在...

    Preact是React的轻量级实现,是React比较好的替代者之一,有着体积小的优点,当然与React之间一定会存在实现上的差异,本文介绍了在 setState 方面的差异之处。

    源码分析

    首先来分析下React以及Preact在setState部分的具体实现。

    (太长不看想偷懒,可以直接下翻看结论)

    React

    关键代码:

    setState 阶段:

    // ReactUpdateQueue.js
    enqueueSetState: function(publicInstance, partialState) {
      ...
    
      var queue =
        internalInstance._pendingStateQueue ||
        (internalInstance._pendingStateQueue = []);
      queue.push(partialState);
    
      enqueueUpdate(internalInstance);
    }

    可以看到React在 setState 的时候不会做任何处理,会把变更直接放到一个专门处理 state 的队列里供组件更新时使用。

    更新阶段:

    // ReactCompositeComponent.js
    updateComponent: function(
      transaction,
      prevParentElement,
      nextParentElement,
      prevUnmaskedContext,
      nextUnmaskedContext,
    ) {
      var inst = this._instance;
      ...
    
      var willReceive = false;
      var nextContext;
    
      if (this._context === nextUnmaskedContext) {
        nextContext = inst.context;
      } else {
        nextContext = this._processContext(nextUnmaskedContext);
        willReceive = true;
      }
    
      var prevProps = prevParentElement.props;
      var nextProps = nextParentElement.props;
    
      if (prevParentElement !== nextParentElement) {
        willReceive = true;
      }
    
      if (willReceive && inst.componentWillReceiveProps) {
        ...
        inst.componentWillReceiveProps(nextProps, nextContext);
      }
      
      // 在此处才计算 nextState
      var nextState = this._processPendingState(nextProps, nextContext); // 此处传入了 nextProps
      var shouldUpdate = true;
    
      if (!this._pendingForceUpdate) {
        if (inst.shouldComponentUpdate) {
          ...
          shouldUpdate = inst.shouldComponentUpdate(
            nextProps,
            nextState,
            nextContext,
          );
        } else {
          if (this._compositeType === CompositeTypes.PureClass) { // 敲黑板,知识点 —— 如果你的组件没实现shouldComponentUpdate,那么把React.Component 换成 React.PureComponent 可以获得基础版优化,提高性能。
            shouldUpdate =
              !shallowEqual(prevProps, nextProps) ||
              !shallowEqual(inst.state, nextState); // 浅比较,可以抄去自己改成属性黑/白名单版
          }
        }
      }
      ...
    }
    
    // ReactCompositeComponent.js
    _processPendingState: function(props, context) { // props: nextProps
      var inst = this._instance;
      var queue = this._pendingStateQueue;
      var replace = this._pendingReplaceState;
      this._pendingReplaceState = false;
      this._pendingStateQueue = null;
    
      if (!queue) {
        return inst.state;
      }
    
      if (replace && queue.length === 1) {
        return queue[0];
      }
    
      var nextState = Object.assign({}, replace ? queue[0] : inst.state);
      for (var i = replace ? 1 : 0; i < queue.length; i++) {
        var partial = queue[i];
        Object.assign(
          nextState,
          typeof partial === 'function'
            ? partial.call(inst, nextState, props, context) // nextProps
            : partial,
        );
      }
    
      return nextState;
    }

    通过上面组件更新的流程代码可以看到:

    • 在 updateComponent 中,在 componentWillReceiveProps 之后才会计算 nextState,所以在 componentWillReceiveProps 中 setState 是可以在当次更新中生效的。
    • 在 _processPendingState 会对队列里的 state 进行叠加,如果修改是函数方式,此处传入的state参数是 nextState,props 是 nextProps。

    Preact

    关键代码:

    setState 阶段:

    // component.js
    setState(state, callback) {
      let s = this.state;
      if (!this.prevState) this.prevState = extend({}, s);
      extend(s, typeof state==='function' ? state(s, this.props) : state);
      if (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);
      enqueueRender(this);
    }

    实现的简单粗暴,在 setState 的时候就进行了合并,会立即改写 this.state,在第一次 setState 时会保留 state 状态到 prevState。由于是立即合并state,如果入参state是函数,props 将只是当前 this.props。

    更新阶段:

    export function renderComponent(component, opts, mountAll, isChild) {
      ...
      previousProps = component.prevProps || props,
      previousState = component.prevState || state,
      previousContext = component.prevContext || context,
      ...
    
      // if updating
      if (isUpdate) {
        component.props = previousProps;
        component.state = previousState;
        component.context = previousContext;
        if (opts!==FORCE_RENDER
          && component.shouldComponentUpdate
          && component.shouldComponentUpdate(props, state, context) === false) {
          skip = true;
        }
        else if (component.componentWillUpdate) {
          component.componentWillUpdate(props, state, context);
        }
        component.props = props;
        component.state = state;
        component.context = context;
      }
      ...
    }

    在更新流程前提取了旧 state,shouldComponentUpdate、componentWillUpdate 之后还原回新值,所以在 shouldComponentUpdate 生命周期中,this.props 将获取的是 prevProps,这里与 React 的逻辑并不一致。

    划重点

    相同点:

    • 在 componentWillReceiveProps 中 setState 都会应用到 nextState。
    • 在 shouldComponentUpdate 中 setState 都会应用到 nextState,但是可以直接操作传入的 nextState。

    不同点:

    • React下 setState 的值不会立即生效,会一直积累到 componentWillReceiveProps,在此之后会进行合并,并提供给后续生命周期。而Preact下 setState 会立即反映到 this.state,但是,在更新组件的生命周期到 render 前(eg: shouldComponentUpdate), this.state 将会是 prevState。
    • shouldComponentUpdate 阶段 setState 虽然不会影响到最终 state 的值,但是Preact下会影响 this.state 的值,比如之后 componentWillUpdate 中的 this.state, 总之此阶段不要 setState 反正也没用。
    • setState 如果使用函数修改,Preact下传入的 props 将会是 prevProps,而React中是 nextProps,在 componentWillReceiveProps 中 setState 时要注意。

    总结

    如果你写的工程需要同时兼容React及Preact的话:

    • 不要利用React下 setState 在同一次组件更新执行前 state 不立即更新的特性,注意多个 setState 之间是否影响,必要时手动保存旧值。
    • 在组件更新生命周期内,除 componentWillReceiveProps 之外不要使用 setState,提供了 nextState 的生命周期,可以直接修改 nextState。
    • 尽量避免使用 setState 函数修改方式,在 componentWillReceiveProps 中使用时,使用生命周期中的 prevProps(this.props) 和 nextProps。

    p.s: antd-mobile 2.0正式版已发布,同时兼容react、preact,轻量、快速、易用的移动端组件库,等你来

    展开全文
  • 二、PreactReact区别有哪些? 三、Preact 是怎么工作的 四、结合实际组件了解整体渲染流程 五、Preact Hooks 结束语 2.1 事件系统 2.2 更符合 DOM 规范的描述 3.3.1 Diff children 3.3.2 Diff 3.3.3 Diff ...

    原创: 宝丁 玄说前端

    本文作者:字节跳动 - 宝丁

    • 一、Preact 是什么
    • 二、Preact 和 React 的区别有哪些?
    • 三、Preact 是怎么工作的
    • 四、结合实际组件了解整体渲染流程
    • 五、Preact Hooks
    • 结束语
    • 2.1 事件系统
    • 2.2 更符合 DOM 规范的描述
    • 3.3.1 Diff children
    • 3.3.2 Diff
    • 3.3.3 Diff props
    • 3.1 JSX
    • 3.2 Virtual DOM
    • 3.3 Preact 的 Virtual DOM 的 Diff 算法
    • 4.1 初次渲染
    • 4.2 执行 setState
    • 5.3.1 useEffect 和 useLayoutEffect
    • 5.2.1 useReducer
    • 5.2.2 useState
    • 5.1.1 useMemo
    • 5.1.2 useCallback
    • 5.1.3 useRef
    • 5.1 MemoHook
    • 5.2 ReducerHook
    • 5.3 EffectHook

    在前端界,React 一定是我们耳熟能详的前端开发框架之一,它的出现可以说是带给了我们全的 Web 开发体验,其中也带来了许多新的概念:JSX、virtual-dom、组件化、合成事件等。当我们想从源码层面去研究它的原理时,由于 React 的源码的庞大和晦涩难懂,这也会变得异常困难。但是在爱好“造轮子”的前端界,我们会发现一些和 React 有着近乎相同的框架,本文的主人公 Preact 也是其一,但是它相对简练的代码,使得我们更好地去学习和研究它的原理。本文将从以下几个方面介绍:

    • Preact 是什么?

    • Preact 和 React 的区别有哪些?

    • Preact是怎么工作的

    • JSX

    • Virtual Dom

    • Preact 的 Virtual DOM Diff 算法

    • Preact Hooks 的实现

    • 一个组件的生命周期

    一、Preact 是什么
    简单而言,Preact 是 React 的 3KB 轻量级替代方案,它拥有着和 React 一样的 API。有同学或许会问,Preact 中的 P 的含义是什么,根据 Preact 的作者表述的是 performance 的含义,这也是 Preact 框架的目标之一。
    我们先来看用 Preact 编写的几个例子:

    image

    图 1

    image

    图 2
    大家第一眼看上去,和 React 的写法基本上一致的,如果仔细的看,大家可能会几个疑问:

    1. h 进行了变量的声明,但是没有使用,这个有什么意义?可以去掉么?
    2. 表单里面使用的是 onInput 方法,而不是在 React 中写的 onChange 方法,这是为什么?

    在这里我先不直接告诉大家答案,这些疑问会在下面的内容中一一为大家解答。
    二、Preact 和 React 的区别有哪些?
    Preact 号称打包后的体积只有 3KB,自然相比 React 而言,在某些方面进行了精简,并且它本身的定位也不是准备从新实现一个 React,所以两者之间肯定是存在一些区别。
    我们在这里主要介绍两者最主要的区别:

    • 事件系统
    • 更符合 Dom 规范的描述

    2.1 事件系统
    通过一个例子,大家或许就能知道两者的区别。

    image

    图 3
    在 React 内部,其自身实现了一套事件合成系统,所以我们一般在 React 的表单组件中使用的都是 onChange 方法来进行组件值的更新,而在 Preact 内部,没有事件合成系统,它直接使用的是由浏览器原生提供的事件系统,这也是为什么 Preact 在表单里面使用的是 onInput 方法,而不是在 React 中写的 onChange 方法。这也是它体积更小的直接原因之一。
    2.2 更符合 DOM 规范的描述
    在 React 中我们想描述一个 DOM 的类名,必须要使用 className, 而在 Preact 中,不仅可以使用 className 来描述,也可以直接使用 class 来描述 DOM 的类名,这也使得 Preact 更接近原生 DOM 规范的描述。
    当然除了这些,Preact 和 React 直接还有一些差别,由于它不是本文的重点,在这里我们就不一一展开介绍,大家可以直接通过 Preact 官网来进一步了解。
    三、Preact 是怎么工作的
    在本节,我们将开始介绍 Preact 的内部工作流程,希望阅读本节过后,大家对 Preact 会有进一步的认识。
    3.1 JSX
    在介绍 JSX 之前,我们先想一下如何在 JS 中来描述 DOM 结构,很多同学可能会想,可以通过浏览器的操作 DOM 的 API 来完成,或者封装成一个工厂函数来进行接收一定的输入,输出就是相应的 DOM。

    image

    图 4
    但是如果每次需要让我们通过这么复杂的方式来进行 DOM 结构的描述,想必 React 的性能再优秀,也能进一步的进行推广。
    这个时候,如果换一种图 5 这样的的方式,是不是大家就很熟悉?

    image

    图 5
    没错,左侧其实就是我们平时写的 JSX 语法,经过 babel 或者其他的插件转换之后变成我们上面所说的函数式的描述,然后再经过一系列的处理,变成我们所熟悉的原生 DOM 的结构,这也是 JSX 产生的本质原因。
    综合来看,其实 JSX 的本质就是 JS 的扩展,它允许你用类似 HTML/XML 的结构,进而编译成类似图 6 的一个函数调用。

    image

    图 6
    这个时候,我们就不得不提 babel 的强大之处了,原来从 JSX转化到函数调用这个阶段是由 React 团队提供的,后面因为 babel 做的更好,更强大,就逐渐演变成了 @babel/plugin-transform-react-JSX 这个核心插件了,那么这个时候我们也可以揭开上文中提到的 h 函数的神秘面纱,正是因为在 Preact 中,JSX 的语法会通过 babel 这个插件转换成一个名称为 h 的工厂函数,类似于在 React 中的 React.createElement 的作用,所以我们才需要去声明 h 函数,虽然我们在实际开发环境上用不到,但是它的作用是体现在 babel 转换后的代码中的,大家也可以通过这个链接来体验 babel 的强大所在。
    3.2 Virtual DOM
    在本节当中,我们将会介绍 Preact 中的 Virtual DOM 是什么?那么它和我们前面说的 JSX 之间有什么关联呢?
    我们前面提到了 h 函数是一个工厂函数,输入我们知道了,是一些描述 DOM 结构的基本信息,那么它的输出是什么呢?我们可以通过下图来揭晓谜底。

    image

    图 7
    从图 7 我们可以看出,其实 h 函数的输出是一个特殊类型的数据结构,而 Virtual DOM 本质上就是一种用来描述 DOM 结构的数据结构,所以 h 函数的输出其实就是我们常说的 Virtual DOM。
    不管在 React 中还是在 Preact 中,最核心的都是 Virtual DOM 的 Diff 算法,怎么把最新的数据所驱动的 DOM 结构表现在页面当中,这个也是大家最关心的环节。
    3.3 Preact 的 Virtual DOM 的 Diff 算法
    在 Preact 中,Virtual DOM 的 Diff 算法可以拆解为三大块。

    • Diff children
    • Diff 这里的 type 指的是组件的类型,主要分成 component、Fragment 和 DOM node 三种。
    • Diff props

    接下来我们会分别仔细的介绍这三块。
    3.3.1 Diff children

    image

    图 8
    在对 children 主要会有两个流程,首先我们先看左侧的流程图,在这个 Diff 阶段,我们会先对新的 children 进行遍历,如果发现新的 child 可以在老的 children 中找到相同的 key,那么会执行 diff <type> 这个阶段,如果没找到相同的 key,会去看是不是相同的类型,比如是不是相同的 DOM node 的类型,或者是相同的构造函数等,找到了的话 也会执行 diff <type> 这个阶段,如果没有找到,会把这个老的 child 放到一个数组当中。
    当对新的 children 遍历完毕之后,我们会执行下一个流程,也就是右侧的流程图,会进行遍历没有使用的 old child 数组,将它们一一unmout 掉,这个时候也会执行相应的生命周期。当这个 child 是一个父组件的话,会对它的 children 重复这个流程,直到全部 unmount。
    在这个阶段,我们也可以得到为什么写 key 是一个非常小但是却非常有用的性能优化手段,因为在一定的程度上它会有效地减少 Diff 过程中所带来的性能损耗。

    3.3.2 Diff

    image

    图 9
    Diff <type> 环节可以说是在整个 Diff 算法中最重要的一个环节,也是最复杂的一个环节。手首先我们会进行新的 vnode 判断它所属于的类型,目前来看,主要包括: Fragment、Component 和 DOM node,其中当判断 vnode 的组件是一个空函数的时候表示的就是 Fragment,而为非空函数的就是 Component 类型。然后根据当前的 vnode 所属的类型进行下一步的处理。
    当 type 为 Fragment 的时候,就直接会将 Fragment 内部的 children 进入到上文中提到的 Diff children 阶段。
    当 type 为 component 时,我们会先判断当前的 vnode 所代表的组件是否已经存在过,如果没有存在则执行 create 操作,同时也会执行相对应的生命周期,如果已经存在对应的组件,那么则会执行 update 操作,并且执行相对应的生命周期函数,在这里我们可以强调一下 shouldComponentUpdate 生命周期函数,当它返回 false 的时候,那么我们就不会再去执行下一步要执行的 render 函数,只有当该生命周期函数不存在或者返回非 false 的时候,我们会继续执行 render 函数,然后继续走该 Diff <type> 阶段。
    当 type 为 DOM node 时,我们首先会判断新老 vnode 是否为同一 node type,如果不同,则会创建新的 DOM 并且代替,如果相同,则会进行更新操作。
    回过头来看 Diff <type> 环节,并且结合我们平时写组件的习惯,可以发现,最后我们写的组件都是原生的 DOM 结构,所以最后都会进入到 Diff DOM node 这一流程中,也是在这一流程中,真正的去创建和更新 DOM。
    3.3.3 Diff props

    image

    图 10
    我相信,大家可能会有点奇怪这一个阶段是做什么的?在上文中我们提到了当两个 DOM node 节点类型相同的时候,会执行更新操作,那么该环节主要是为这个更新操作而服务。
    它的原理很简单:先循环老的 DOM 的 props,如果它不在新的 DOM 上,那么就会将它设为空,然后循环新的 props,然后和老的 props 中相同的 prop 去做比较,然后设置最新的 prop 的值。
    到这里,我们整个的 Virtual DOM 过程也就完成了,Preact 内部的工作原理也基本上介绍完了,但是大家可能还比较难和一个真实的组件来相关联,接下来我们通过一个真实的组件,来将上面的过程进行串联,加深大家对它的理解。
    四、结合实际组件了解整体渲染流程
    首先,我们先编写一个如下图的 Clock 组件:

    image

    图 11
    接下来我们会通过两个阶段来介绍:

    1. 初次渲染
    2. 执行 setState

    为了方便介绍,我在画了一个流程图,大家可以搭配图 12 的流程图(点击这里获取高清大图)和文字来看,方便大家更容易理解。

    image

    图 12
    4.1 初次渲染

    1. 入口函数为 render(<Clock />, document.body)
    2. 将 JSX 语法转化成 h 函数的形式之后,也就是 createElement 函数来创建一个用来描述子组件为 Clock 组件的 vitrual node(下文简称为 vnode),类似于这种结构 {type: Fragment, children: [Clock], props: null }
    3. 将该 vnode,用数组包裹起来,然后送入到 Diff children 阶段
    4. 当 Diff children 阶段结束之后,会执行 commitRoot 方法来执行挂载组件的 componentDidMount 方法,内部主要是通过 promise 或者 setTimeout 来做有异步的处理。
    5. 接下来我们主要来进行描述 Diff children 的流程。
    6. 因为是第一次渲染,所以我们都没有老的 vnode 也就没有所谓的是否具有相同 key 或者相同 type 的新老 vnode。
    7. 直接进入到 diff(newChild, oldChild) 这一阶段。
    8. 判断我们的 vnode 的 type 是一个 component, 并且是一个新的组件,这个时候我们创建新组件,并且执行对应的生命周期,然后调用我们的 render 函数。
    9. 因为 render 函数的返回值其实依然是一个 vnode,所以会继续流转到 diff(newChild, oldChild) 这一个阶段,直到判断 type 是 DOM node 时,会执行 DOM 的操作变化。

    4.2 执行 setState

    1. 我们可以从流程图中看到,其实 setState 本质上的操作,会将它所在的 vnode 送入到 diff(newChild, oldChild) 中,而 newChild 和 oldChild 的主要区别其实就是 state 的变化。
    2. 因为 Clock 组件是一个 component 类型的 vnode,所以我们会继续判断它是不是新组件,很显然已经不是了,于是会执行对应的生命周期,如果没有 shouldComponentUpdate 生命周期函数或者返回了 true,那么我们会继续执行 render 函数,不然我们会停止组件的渲染。
    3. 这个时候 render 函数中,已经有了我们最新的 state了,那么对应的接下来会继续走 diff(newChild, oldChild) 流程,直到将更改的 state 值在真实的 DOM 结构中的 props 中体现出来。

    在这里,整个 Clock 组件的渲染过程就介绍完了,也希望大家通过这个例子,能够对 Preact 的底层工作原理有了更深的认识。
    五、Preact Hooks
    Hooks 是 React v16.8 版本中引入的新 API,Preact 作为 React 的可代替方案,自然也会跟上这个变化,在 Preact 中,Hooks 是作为一个单独的包引入的,包括注释总代码仅 300 行。
    在 Preact 中,Hooks 可以分为三类:

    • MemoHook
    • ReducerHook
    • EffectHook

    接下来我们将通过这三类来介绍。
    5.1 MemoHook
    MemoHook 的主要作用是用来做一些性能优化的 Hook 集合。并且在 MemoHook 内部,有一个通用的数据结构,用来表示该 Hook 内部的数据结构。

    image

    图 13
    5.1.1 useMemo
    useMemo 的作用主要是:我们可以记住计算的结果,并且仅在其中一个依赖项发生更改时才重新计算它。

    image

    图 14
    当我们每次进行渲染的时候,都会去执行 expensive 这个非常耗费性能的计算,这样下来,会造成一定的性能的损耗,那我们可以使用 useMemo 来进行优化。这样如果 expensive 依赖的值没有变化,就不需要执行这个函数,而是取它的缓存值。

    image

    图 15
    其实它的内部原理很简单,我们可以通过下图通过它的源码进行分析。

    image

    图 16
    本质上就是进行前后比较它的依赖的数据是否发生了改变,如果发生了变化,则调用传入的 callback 函数,否则就直接返回原来的内部的 state 的值。
    5.1.2 useCallback
    作用:它可用于确保只要没有依赖项发生更改,返回的函数将始终保持引用相等。

    image

    图 17
    用上图的例子来说明它的作用就是,当它的依赖项 a、b 未发生变化的时候,onClick 这个函数始终是相同的。
    实际上 useCallback(fn, deps)useMemo(() => fn, deps) 是等价的,因为 useCallback 就是用 useMemo 来实现的,只是它返回的是一个没有进行调用的 callback,所以上图的代码可以等价于:

    image

    图 18
    即当 a、b 不发生变化的时候,() => console.log(a, b) 也就不会发生变化。
    5.1.3 useRef
    作用:获得对功能组件内部的 DOM 节点的引用。 它的工作原理类似于 createRef。

    image

    图 19
    它的原理也是十分的简单。

    image

    图 20
    本质上就是初始化的时候创建一个内部状态为 {current:initialValue} 的组件,且不依赖任何数据,需要则通过手动赋值修改。
    5.2 ReducerHook
    ReducerHook 的主要作用是用来做一些性能优化的 Hook 集合。并且在 ReducerHook 内部,有一个通用的数据结构,用来表示该 Hook 内部的数据结构。

    image

    图 21
    5.2.1 useReducer
    useReducer 的使用方式和 Redux 非常像。

    image

    图 22
    对于使用过 Redux 的同学来说,这样的用法应该会很容易接受和熟悉。
    我们可以通过源码来进行分析它的实现原理。

    image

    图 23
    更新 state 就是调用 dispatch,也就是通过 reducer(preState, action) 计算出下次的 state 赋值给 _value。然后调用组件的 setState 方法进行组件的 Diff 和相应更新操作。
    5.2.2 useState
    useState 大概是平时在开发过程中最常使用的 Hook,它类似于 class 组件中的 state 状态值。

    image

    图 24
    它的原理很简单,就是利用 useReducer 来进行实现的,也就是 useState 其实只是传特定 reducer 的 useReducer 一种实现。

    image

    图 25
    5.3 EffectHook
    “副作用”一词在很多参与过 React 相关的项目开发的同学来说,肯定不会陌生,无论是要从 API 获取某些数据还是要对文档触发效果,基本上可以发现 EffectHook 几乎可以满足所有需求。 这也是 Hooks API 的主要优点之一,它使你的思维重塑了对效果的思考,而不是对组件生命周期的思考。
    在整个 EffectHook 中,都贯穿了下面这样的通用数据结构。

    image

    图 26
    5.3.1 useEffect 和 useLayoutEffect
    这两个 Hook 的用法完全一致,都是在 render 过程中执行一些副作用的操作,可来实现以往 class 组件中一些生命周期的操作。区别在于, useEffect 的 callback 执行是在本次渲染结束之后,下次渲染之前执行。useLayoutEffect 则是在本次会在浏览器 layout 之后,painting 之前执行,是同步的。

    image

    图 27
    使用的方式和前面的 Hook 的使用方式基本上一致,传递一个回调函数和一个依赖数组,数组的依赖参数变化时,重新执行回调。

    image

    图 28
    它们的实现机制,稍微有些复杂,我们先看源码。

    image

    图 28
    从代码上来看,它们的实现几乎一样,唯一的区别是进入的回调分别是 _renderCallbacks、_pendingEffects,从而达到了不同时机下进行渲染,这一块的具体逻辑,大家可以参考这篇文章了解更多的细节。
    整体来看,Preact 的 Hook 模块的代码实现虽然内不多,但是是却体现出了它的精炼以及 Preact 优秀的架构。
    结束语
    最后希望大家能够通过本文,对 Preact 的整体工作机制有了更加深入的理解,有时间的同学也可以自己尝试阅读 Preact 的源码并结合本文,我相信阅读之后一定能够对 React 的理解更上一层楼。再次感谢大家!
    欢迎关注“玄说-前端”微信公众号

    image

    福利:

    扫描下方二维码,加”助理“好友,回复”加群“,进入“玄说-前端” 微信群,一起讨论前端技术,更有大厂内推机会。

    image

    展开全文
  • 类似Linked State但用于Refs。支持Preact与React.
  • 就像React和许多其他类似的库一样, Preact是虚拟DOM组件范例的实现。 与React不同,它只有3KB的大小,并且在速度方面也胜过它。 它是由杰森·米勒(Jason Miller)创建的,并以著名的宽松和开源MIT许可证提供。 ...

    就像React和许多其他类似的库一样, Preact是虚拟DOM组件范例的实现。 与React不同,它只有3KB的大小,并且在速度方面也胜过它。 它是由杰森·米勒(Jason Miller)创建的,并以著名的宽松和开源MIT许可证提供。

    为什么要使用Preact?

    徽标徽标 Preact是React的轻量级版本。 如果您喜欢使用React构建视图,但是性能,速度和大小是您的首要任务,例如移动Web应用程序或渐进式Web应用程序,则您可能更喜欢使用Preact作为轻量级替代方案。

    无论您是开始一个新项目还是开发一个现有项目,Preact都可以为您节省大量时间。 你并不需要推倒重来努力学习新的图书馆,因为它类似,和兼容,作出React-到如此地步,可以使用现有的React封装,它只有一些混淆,多亏了兼容层preact-compat

    利弊

    React和Preact之间有很多区别,我们可以概括为三点:

    • 功能和API :Preact仅包括React API的一个子集,而不是React中所有可用的功能。
    • 大小 :Preact比React小得多。
    • 性能 :Preact比React快。

    那里的每个图书馆都有自己的优缺点,只有优先考虑才能帮助您确定哪个图书馆适合您的下一个项目。 在本节中,我将尝试列出这两个库的优缺点。

    事前优点

    • Preact比React轻巧,小巧(压缩后只有3KB)并且比React快(请参阅这些测试 )。 您也可以通过此链接在浏览器中运行性能测试。
    • Preact在很大程度上与React兼容,并且具有与React相同的ES6 API,这使得采用Preact作为用于在项目中构建用户界面的新库或出于性能原因将React与Preact交换而变得非常容易。
    • 它具有良好的文档和可从官方网站上获得的示例。
    • 它具有功能强大且正式的CLI,可快速创建新的Preact项目,而无需担心Webpack和Babel的配置。
    • 许多功能都受React上已经完成的所有工作的启发。
    • 它还具有独立于React的自己的高级功能集,例如Linked State

    React专家

    • React支持单向数据绑定。
    • 它得到了一家大型公司Facebook的支持。
    • 官方网站和网络上的优质文档,示例和教程。
    • 大型社区。
    • 在Facebook网站上使用,该网站在全球拥有数百万的访问者。
    • 具有针对Chrome的官方开发人员调试工具扩展程序。
    • 它具有Create React App项目样板,可快速创建零配置的项目。
    • 它具有结构良好且复杂的代码库。

    React缺点

    • 与Preact或其他现有的类似库相比,React具有相对较大的大小。 (React后的缩小的源文件大小约为136KB,缩小并压缩后约为42KB。)
    • 它比Preact慢。
    • 由于其复杂的代码库,新手开发人员很难做出贡献。

    注意:我在撰写本文时列出的另一个缺点是,React具有与BSD许可证配对的授权专利条款,使其在法律上不适合某些用例。 但是, 在2017年9月 ,React许可证转换为MIT,从而解决了这些许可证问题。

    预设缺点

    • Preact仅支持无状态功能组件和基于ES6类的组件定义,因此没有createClass
    • 不支持上下文
    • 不支持React propTypes。
    • 比React更小的社区。

    Preact CLI入门

    Preact CLI是Preact的作者Jason Miller创建的命令行工具。 它使创建新的Preact项目非常容易,而又不会陷入配置复杂性的困扰,所以让我们从安装它开始。

    打开终端(Linux或macOS)或命令提示符(Windows),然后运行以下命令:

    npm i -g preact-cli@latest

    假设您在本地开发计算机上安装Node和NPM ,它将安装Preact CLI的最新版本。

    现在,您可以使用以下命令创建项目:

    preact create my-app

    或与此相关的东西,如果您想以交互方式创建您的应用程序:

    preact init

    接下来,在应用程序的根文件夹中导航并运行以下命令:

    npm start

    这将启动实时重载开发服务器。

    最后,当您完成应用程序的开发时,可以使用以下代码构建生产版本:

    npm run build

    为您的第一个Preact应用揭秘

    成功安装Preact CLI并生成应用后,让我们尝试了解使用Preact CLI生成的简单应用。

    Preact CLI生成以下目录结构

    ├── node_modules
    ├── package.json
    ├── package-lock.json
    └── src
        ├── assets
        ├── components
        │   ├── app.js
        │   └── header
        ├── index.js
        ├── lib
        ├── manifest.json
        ├── routes
        │   ├── home
        │   └── profile
        └── style
            └── index.css

    components文件夹包含Preact组件,而routes文件夹包含用于每个应用程序路由的页面组件。 您可以将lib文件夹用于任何外部库,将CSS样式的style文件夹,以及用于图标和其他图形的assets使用。

    请注意manifest.json文件,该文件类似于package.json但适用于PWA(渐进式Web应用程序)。 借助Preact CLI,您可以立即获得完美得分的PWA。

    现在,如果打开项目的package.json文件,您将看到主入口点设置为src/index.js 这是此文件的内容:

    import './style';
    import App from './components/app';
    
    export default App;

    免费学习PHP!

    全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

    原价$ 11.95 您的完全免费

    如您所见, index.js./components/app**导入样式和App组件,然后将其默认导出。

    现在,让我们看看./components/app里面的./components/app

    import { h, Component } from 'preact';
    import { Router } from 'preact-router';
    
    import Header from './header';
    import Home from '../routes/home';
    import Profile from '../routes/profile';
    
    export default class App extends Component {
        handleRoute = e => {
            this.currentUrl = e.url;
        };
    
        render() {
            return (
                <div id="app">
                    <Header />
                    <Router onChange={this.handleRoute}>
                        <Home path="/" />
                        <Profile path="/profile/" user="me" />
                        <Profile path="/profile/:user" />
                    </Router>
                </div>
            );
        }
    }

    该文件导出默认类App ,该类扩展了从preact包中导入的Component类。 每个Preact组件都需要扩展Component类。

    App定义了render方法,该方法返回一堆HTML元素和Preact组件,以渲染应用程序的主用户界面。

    div元素内部,我们有两个Preact组件: Header (呈现应用程序的标头)和Router组件。

    Preact Router与最新版本的React Router(版本4)相似。 您只需要用<Router>组件包装子组件,然后为每个组件指定path属性。 然后,路由器将负责呈现组件,该组件的路径属性与当前浏览器的URL相匹配。

    值得一提的是,Preact Router非常简单,与React Router不同,它不支持嵌套路由和视图组合之类的高级功能。 如果需要这些功能,则必须使用别名为preact-compat的React Router v3,或者最好使用比v3更强大且不需要任何兼容性层的最新React Router(版本4)。直接与Preact一起使用。 (有关示例,请参见此CodePen演示。)

    预先兼容层

    preact-compat模块允许开发人员从React切换到Preact,而无需将从React和ReactDOM的导入更改为Preact,或将现有的React软件包与Preact一起使用。

    使用preact-compat很容易。 您要做的就是首先通过npm安装它:

    npm i -S preact preact-compat

    然后设置您的构建系统以重定向导入,或将reactreact-dom要求重定向到preact-compat 例如,对于Webpack,您只需要向webpack.config.js添加以下配置:

    {
      "resolve": {
        "alias": {
          "react": "preact-compat",
          "react-dom": "preact-compat"
        }
      }
    }

    结论

    Preact是React的不错选择。 它的社区正在稳定增长,越来越多的Web应用程序正在使用它。 因此,如果您要构建具有高性能要求的Web应用程序,或者为速度较慢的2G网络构建移动应用程序,则应考虑使用Preact-作为您项目的第一个候选视图库,或作为React的直接替代品。

    翻译自: https://www.sitepoint.com/using-preact-react-alternative/

    展开全文
  • 为什么选 PreactFast 3kB alternative to React with the same ES6 API.React 的 3kb 轻量化方案,拥有同样的 ES6 API体积小。React v15.6.1 有 49.8kb,最新的 React v16.0 小了很多,有 34.8kb。而 Preact 官网...
  • 就像React和许多其他类似的库一样, Preact是虚拟DOM组件范例的实现。 与React不同,它只有3KB的大小,并且在速度方面也胜过它。
  • linkState 将事件绑定至state,支持PreactReact.
  • React 的替代方案 Inferno 发布 1.0 版本 David Iffland 张卫滨 阅读数:23152017 年 1 月 15 日 类似于 React 的 JavaScript 库 Inferno 发布了 1.0 版本,对于那些熟悉 React,但对现代化 JavaScript 库的大小...
  • 此分支已集成react与preact。 背景 最近接手了互动视频的项目,做了一个月的运营活动。跟基础功能不同,运营活动更为轻量。因此许多同事并不想用那么“重”的React。但同时,大家由于之前度过React的上手痛苦期后,...
  • React 替代方案,轻快,仅有 3KB。提供了相同的 ES6 API,并且也有组件和 Virtual DOM
  • React-router is the community favourite routing solution - it can handle all of your complex routing needs and in this lesson we’ll cover what’s needed to enable it’s use within Preact....
  • 作者:荒山https://juejin.im/post/5cfa29e151882539c33e4f5eReact 的代码库现在已经比较庞大了,加上 v16 的 Fibe...
  • 本文介绍了 React 核心的 Diff 算法,并以 Preact 中的 Diff 算法实现作为示例,提供了相关函数的具体分析。
  • 使用环境: node -vv10.19.0 npm -v6.13.4 VSCode 1、在src\components\下面创建文件夹Like,创建src\components...import React, { Component } from 'react' export default class Like extends Component { ...
  • 走势图是通过统计最新的数据,并前一年的数据进行比较而生成。数据来源于 npm trends 的每日下载量。 前端框架三巨头 React、Angular 和 Vue,虽然都很受欢迎,且保持着上升趋势,但 Vue 爆发力最强,但在使用率上...
  • eact 的代码库现在已经比较庞大了,加上 v16 的 Fiber 重构,很容易初学者陷入...PreactReact 的缩略版, 体积非常小, 但五脏俱全. 如果你想了解 React 的基本原理, 可以去学习学习 Preact 的源码, 这也正是本文...
1 2 3 4 5 ... 20
收藏数 895
精华内容 358
关键字:

preact与react的区别