Thinking In Life Why We are Living.
Hooks是React 16.8新加特性,这篇博客记录于v16.9.0。不能在class组件里使用Hooks,但是你可以通过使用state和React的一些特性而不用写class。
何时使用
当你写函数组件时,发现自己需要使用state的时候。
useState
无Hooks的无状态组件
1 | const Example = (props) => { |
Hooks使你可以实现可复用的状态组件
1 | import React, { useState } from 'react'; |
useState(initial)
只接受一个参数,即count
的初始值。
返回值是一个包含当前组件的state和一个更新它的函数的数组,然后利用解构赋值赋值给我们定义的变量名(名字我们自己起的)。
如果需要存储多个值在state
里,需要调用useState()
多次。
count
是我们定义的state
属性,可以是任何名字。类似于class
组件里的this.state.count
;
setCount
是用来更新count
的,可以是任何名字。类似于class组件里的this.setState()
。
定义多个
1 | function ExampleWithManyStates() { |
useEffect
类似于
class
组件中componentDidMount
和componentDidUpdate
分两种情况来学习useEffect
(1)第一种是effect不需要消除
有的时候我们希望产生同一个effect(比如请求),不管是Didmount还是DidUpdate,如果是class组件,要在componentDidMount
和 componentDidUpdate
两个函数里写同样的代码,没有一个统一的方法。而Hooks
提供了useEffect
完成了这一需求。
1 | useEffect(() => { |
类似于
1 | componentDidMount() { |
这里要注意,函数式组件和class组件渲染的不同,函数组件是调用函数(相当于class组件中的render()函数)所以每次更新函数式组件都要重新调用组件函数,而class组件一直存在内存里(只要不卸载它)(new的一个对象),每次更新只要调用render()就行了。
解释
默认,每次更新或者第一次render
都会调用useEffect
里的回调。
因为在同一个函数作用域链里,所以,useEffect
能直接访问useState()
里的变量。
(2)还有一种是需要在组件卸载的时候清除effect
class组件的写法
1 | componentDidMount() { |
Hooks的写法
1 | useEffect(() => { |
解释
cleanup函数名并不是闭包必须的,可以返回一个匿名/箭头函数。
cleanup执行时机:每次组件卸载(unmount)都会执行。
1 | // Mount with { friend: { id: 100 } } props |
useEffect的第二个参数
class组件写法
1 | componentDidUpdate(prevProps, prevState) { |
hooks写法
1 | useEffect(() => { |
两者效果是一样的。
注意
数组里的比较使用 === 运算符,只要数组一项改变,就会重新执行
useEffect()
(对有cleanup
的useEffect
也同样有效)
如果你只需要在mount
和unmount
时只执行一次useEffect
,传入[]
空数组。
题外
Babel
默认只转换新的JavaScript
句法(syntax
),而不转换新的API
,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise
等全局对象,以及一些定义在全局对象上的方法(比如Object.assign
)都不会转码。而且像import
和export
这两个命令现在在任何浏览器中都是不支持的, 同时babel也无法将其转换为浏览器支持的ES5。
原因在于:babel
只是个翻译,假设a.js
里 import
了 b.js
, 对a.js
进行转码,只是翻译了a.js
,并不会把b.js
的内容给读取合并进来, 如果想在最终的某一个js
里,包含 a.js
,b.js
的代码,那就需要用到打包工具。(哎,写个demo
都要用webpack
的嘛)
配置webpack
的一些坑
Error Decoder
Target container is not a DOM element.
如果要手动引入标签,要把bundle.js
放在ReactDOM.render(<MyComponent />, DOMContainer);
后面。
打包的时候出现找不到react、react-dom模块
1 | $ npm install --save react |