props
对象并返回一个
React 元素
,它本质上就是基础的
JavaScript函数。
Class组件的写法建立方法有两种,下图是兼容es5写法的React.createClass定义的组件,这也是react一开始的建立组件的方法。 前端
propTypes
用来处理校验定义属性的类型校验,PropTypes是从React中获取的,在React16.0.0版本之后废弃了这种写法,PropTypes被单独提取到prop-types
包中,因此先比较新的版本中,咱们要进行类型校验,须要手动引入 prop-types 这个模块getInitialState
用来初始化state,getDefaultProps
用来定义props的默认属性值,这两个函数的用法有点相似于如今vue中的data和props方法render函数
,它会返回 react node用来渲染视图这是一个如今常见的ES6的class react组件写法 vue
Component API
, 配合一些代码转换工具咱们可使用最新的es语法render函数
用来渲染视图,因为es6支持了方法简写,render以及其余定义的函数已经不须要声明function 关键字super
调用,ES6 规定,子类的构造函数必须执行一次super方法,若是子类没有定义constructor方法,这个构造函数会被默认添加并调用super。 若是咱们声明了constructor函数,就必须在构造函数里调用super,只有在正常调用super(props)方法后才能够访问this对象,在constructor中若是要访问this.props须要在super中传入props,固然也能够直接经过props访问。可是不管有没有定义constructor,super是否传入props参数,在react的其余生命周期中this.props都是可使用的,这是React自动附带的。字段名 = 引用值
。 在 constructor 方法被执行前, 实例上已经被赋值了该字段内容。
因此如今比较流行的写法是这样的 根据公有类字段语法 咱们能够直接经过
字段名 = state
对象内容来声明state对象。 因为箭头函数没有本身
this,在这里它会指向当前类的实例。借用公有类字段的提案,咱们能够直接声明一个 箭头函数来修正方法的this指向。 这样咱们就无需在构造函数里去建立state。也不须要在构造函数里写一大堆function绑定this。若是没有其余的操做,咱们就彻底能够省略构造函数。
PureComponent
内部是继承React.Component来的,在React.Component组件中咱们可使用shouldComponentUpdate来判断是否重发从新渲染,而 React.PureComponent 内部使用 shallowEqual 进行浅比较。 浅比较会比较更新先后的state和props的长度是否一致,判断是否新增或者减小了props或state的数据个数。 而后它还会调用内部的objectis
方法浅层对比先后的state和prop,objectis相似于es6的 Object.is方法, Object.is 相似于 === 全等运算符,只是在比较 +0 跟 -0 时表现的不太同样, === 返回的是true 而他是false。node
上图是一个很简单的函数组件例子,虽说函数组件本质上就是 一个 JavaScript 函数, 在例子里看起来没有任何使用react的api或者方法,可是咱们仍然引入了react,这是由于在组件内部返回的react 元素 使用了 jsx,他实质上是React.createElement
的语法糖,配置好babel就能够为咱们编译jsx,简化了咱们写createElement的过程。react
函数组件不须要声明类,能够避免大量的譬如extends或者constructor这样的代码 也不须要处理 this 指向的问题。 更加纯粹的是一个函数就是一个组件,React 官方说的 React 组件一直更像是函数,咱们写函数式组件彷佛也是更加贴近react的原则。 引用透明性是函数式编程的一个概念,我我的以为函数组件遵循了纯函数的概念。webpack
引用透明性是函数式编程里的概念。 这是一个 redux 里的 reducer 函数。在 redux 里 reducer
须要被定义为一个纯函数,它符合纯函数的几个定义:git
不少时候一开始咱们写的代码或者组件都是比较简单的,咱们可能会选 函数组件来完成一个 简单的功能模块。可是越到后面可能功能就变的越发的复杂了,函数组件内可能须要一些本身的状态或者生命周期了。 这时候想要实现这些功能可能就须要把它借助 高阶组件 或者 render props 帮它包装一层class 的父组件,这样它就间接的拥有了状态跟生命周期。可是这也都只是在函数组件外借助了 class 组件的能力。es6
因为函数组件在每次渲染时候,组件内部都会从上到下从新执行一遍,它也没有办法有本身内部的状态,也没法产生反作用,为了加强函数组件,hook
就出现了。github
Vue 在放出可能到来 3.0 更新的内容,上图就是此次更新变更比较大的 funtion based api
.web
对比右侧2.0的写法, template 就是 以前的模板语法。比较特殊的就是 setup 函数。 这里的value是一个包装对象,它就是组件内部的状态,这个看起来跟react 的 usestate hook 仍是很是像的。 onMounted 对应的就是之前的生命周期函数 mounted,方法最后的返回对象有点像以前的data方法里的内容被绑定到了template模板语法上,setup 看起来就是一个简单的函数。typescript
vue做者提到了function based api
借鉴了
react hook
的思想。 因为
typescript对函数的类型推导能力比较好,以前vue组件比较流行的那种对象的写法如今看起来也变成了setup这样一个函数了。 至于更灵活的逻辑复用能力,这个在后面会看到是如何进行逻辑复用的。
React 16.8
的新增特性。它是在函数组件的基础上引入了一些新API,可让你在不编写
class 的状况下使用
state 以及其余的 React 特性。
咱们看到这里使用了一个 useState
的API,它能够在调用时传入参数,而且返回一个数组。数组中有两项内容,第一个是状态(state)、第二个是设置状态(setState),使用es6 数组解构的特性,咱们能够根据咱们的须要去语义化命名,useState中的init参数只会在方法在第一次初始化之后,即便函数组件被更新,它的state也不会被重置,因此它能够一直保留着当前的状态。 这也就让函数组件拥有了内部状态,以及生命周期。
在react 的 class 组件中,咱们会定义一个数组类型的 state,在对修改了引用中data里的一些值后,调用this.setState 方法会触发从新渲染,可是在一样的操做在hook里并不会触发更新。
调用咱们设置 hook 的 setData 更新函数,数并传入当修改过引用类型的data 去触发更新时,React将跳过子组件的渲染及 effect 的执行。(React 使用 Object.is 比较先后 state)因为引用地址没变化 因此不会发生从新渲染。 咱们可使用图中下面的两种方式浅拷贝对象 而后再进行操做,便可解决这一问题。useEffect的规则以下:
React内部会建立对应的 hook 节点,react 第一次初始化组件时内部会将这些节点结构经过 next 依次链接起来,造成一个单向链表结构,每一次调用setter 就 dispach 一个对应的action方法,将action存储在queue中。
在后续触发渲染时,react 会调用 queue 队列中的内容,queue 也是一个链表结构,它是收集咱们调用setter方法,queue 会依次执行内部的action,从而获取到最新的状态值,状态值会被更新到memorizedState上,而后将状态反应到对应的hook字段中造成绑定。因此当咱们打乱或者增长减小hooks时,会形成hook内部顺序错误,从而致使没法正常工做。
上图是组合成的一个hooks单向链表结构,内部依次经过next指向下一个hook。
尝试经过修改hook数量,在第一次初始化时候咱们调用了三个usestate hook,react也会在它内部依次收集了三个hook。 第一次渲染时,页面能够正常的渲染出内容,当咱们点击了一个 setter 方法,从新触发了渲染时,会因为 hook 数量比以前的少而致使页面错误,没法正常渲染。因此保证每次都是相同的调用顺序才能正确的使用hook。
Hooks API是专门为函数组件设计的,因此咱们只能在函数式组件内部或者自定义的hook中使用hooks,包括usestate、useeffect、userref 等以及自定义的hook api。并且自定义hook,也是没法在class组件内部使用的。 固然正常的函数组件,即便在内部使用了hook,咱们能够也class组件内部复用该函数组件,这个是不会影响的。componentDidMount: 当第二个参数为空数组时,回调只会被触发一次,相似于componentDidMount。
componentDidUpdate: 当 useEffect 不传入第二个参数时,在第一次初始化和每次从新渲染后都会触发回调。这与 componentDidUpdate 有些不一样,componentDidUpdate 生命周期在初始化挂载的时候不会被调用,咱们可使用 useRef 钩子来存储一个值来判断函数是否为第一次调用useRef返回一个可变的ref对象,它不只能够绑定dom的引用,也能够用来存储一些值。其.current
属性被初始化为传递的参数(initialValue)。返回的对象将持续整个组件的生命周期。变动 .current
属性不会引起组件从新渲染。
componentWillUnmount 前面提到每一个 useEffect 均可以返回一个清除函数。配合这一特性,咱们能够任然将第二个参数设置为一个空数组,这样清除函数会在组件卸载前被调用,咱们能够在这里面清除一些事件监听器等。更方便的是咱们能够将 didMount 和 unMount 写在同一个 useEffect 钩子中。
componentWillReceiveProp: 咱们想要模拟以前的 componentWillReceiveProps 生命函数,能够将第二个参数设为须要观察的props参数。为了比对先后的 props 变化,能够用 useRef 来存储旧的props来达到目的。setState的第二个参数 咱们知道在使用setState方法时,能够传入第二个参数,这个参数是个回调函数,它在设置完 state 之后 会被调用。 咱们在hook里也能够经过用useEffect 钩子传入要监听的 state,当该state更新之后,回调函数会被调用。
React 规定 自定义hook 须要用 use 开头来定义,自定义hook虽然不是一个组件,它不须要返回 React Node 元素节点,若是返回了元素,它就又变成的一个函数组件,可是虽然这样,它一样的能够在方法内部使用 状态 usestate 和生命周期 useeffect 等其余的 hooks。他拥有本身的内部状态和生命周期。
比较特殊的是 自定义hook 返回的内容能够任何类型,你能够单纯的返回一个值,也能够返回一个对象或者数组甚至是方法,返回的内容取决于在调用你建立的自定义hook时所须要的一些属性。
咱们在这里定义了一个名为 useOnline 的自定义hook, 咱们用它来判断当前的网络链接状态。首先hook的方法名是以use开头的,后面的名字能够根据你的意愿来定义,大部分时候hook都会遵循驼峰命名法,只要是以use开头,后面的定义是没有限制的。不过我尝试了一下即便不使用use开头建立的自定义hook其实也是正常运行的。react 约定以use开头是为了经过一些自动检查工具来来校验 这些use开头的hook内部是否违反了 hook的使用规则。不过仍是最好遵循使用use开头,驼峰命名这样一个约定。
而后调用 usestate 建立一个 自定义hook内部的状态, 传入了 navigator online 初始化当前的网络状态,而且在自定义 hook 内部拥有了本身的状态。
接着在使用 useeffect 钩子内,咱们须要监听网络状态的变化,联网或者断网的监听方法只须要在组件建立时调用一次便可,因此咱们在传递useeffect的第二个参数时,只传递了一个空的数组,这样它就只会在 didmount 时被调用一次。
一样的在销毁组件时,咱们也须要清除掉这些监听事情。在 effect 钩子的返回函数中清理掉这两个监听方法便可
最后咱们将 当前的状态值 做为自定义hook的返回值,这样就完成了一个监听网络状态的自定义hook。
咱们在一个最简单的函数组件中引入这个hook。 而后在函数组件内咱们调用这个自定义hook,hook会返回当前的网络状态,这是一个很简单的函数组件,咱们只渲染当前的网络状态。
当咱们渲染出组件时候他渲染出了当前的网络状态, 当咱们切换为离线状态时,能够看组件被从新渲染出了当前的网络状态值。这样,当咱们建立出一个自定义hook时 就能够在不少地方调用直接复用这段代码,达到了逻辑复用的目的。
不过你们可能以为这不就是抽象一个方法么? 好像没有自定义hook 咱们也能够把一些方法抽象到一些工具函数中, 写一些 helper 或者 utils来完成这些功能 。 可是实际上是不同的,自定义的hook强大之处在于拥有状态,当状态值改变时,它能够触发调用组件的从新渲染,并且自定义hook能够跟随着组件的生命周期,在不一样的生命钩子阶段,咱们能够处理一些事件。
咱们能够选择本身去 实现 一个 useDidMount 自定义hook,实现起来也很是简单。只须要在钩子内部调用 useeffect hook,将它的第一个参数传递为咱们自定义钩子的回调函数参数,将第二个可选的参数设为一个空数组,这样就只会在 didmount时候被调用一次。
这个开源项目帮咱们收集了一系列已经封装好的自定义hook,好比这些生命周期钩子,咱们只须要引入便可实现这些生命周期。包括一些 didMount, unmount, update 等钩子。
分享一个React Hook弧形进度条组件react-arc-progress,这个以前是一个es6方式写的插件,而后以前为了跟进 react hook,将它改形成了一个 react 组件。
重复的造轮子确定是没有意义的,因此要添加一些独特的功能让它变得更不同些:
GitHub地址,请给个star吧 ◔ ‸◔