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
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里并不会触发更新。
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。
componentDidMount: 当第二个参数为空数组时,回调只会被触发一次,相似于componentDidMount。
useRef返回一个可变的ref对象,它不只能够绑定dom的引用,也能够用来存储一些值。其.current
属性被初始化为传递的参数(initialValue)。返回的对象将持续整个组件的生命周期。变动 .current
属性不会引起组件从新渲染。
componentWillUnmount 前面提到每一个 useEffect 均可以返回一个清除函数。配合这一特性,咱们能够任然将第二个参数设置为一个空数组,这样清除函数会在组件卸载前被调用,咱们能够在这里面清除一些事件监听器等。更方便的是咱们能够将 didMount 和 unMount 写在同一个 useEffect 钩子中。
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吧 ◔ ‸◔