Hooks是React16.8版本中的新特性,它能够在不使用class声明的组件中使用state和React特性。react
Tip: React v16.8.0已经支持Hooks。当咱们进行更新时,别忘了更新其余相关依赖包,包括React DOM等。React Native将会在下一个稳定版本支持Hooks。数组
在使用Hooks以前咱们必须知道的几件事:bash
那么Hooks出现的动机是什么:函数
先来介绍第一个useState。能够在函数组件(function component)使用它。它在的做用是添加本地状态到当前组件。React会一直维持在这个state。useState将会有两个返回值:当前的state和一个更新state的方法。 调用useState时传入的参数表示着initial State。咱们能够屡次调用useState在同一个组件中,表示建立多个状态。ui
import React, { useState } from 'react'
const HookDemo = ({}) => {
const [count, setCount] = useState(0)
const [number, setNumber] = useState(2)
const [todos, setTodos] = useState([{text: 'huzhiwei'}])
const setHandle = () => {
todos[0].text = 'jp'
setTodos(Object.assign({}, todos))
}
return (
count: {count}
number: {number}
todos: {todos[0].text}
<button onClick={()=>setCount(count+1)}>count handler</button>
<button onClick={()=>setNumber(number+1)}>number handler</button>
<button onClick={()=>setHandle()}>todos handler</button>
)
}
复制代码
咱们可能执行过请求获取数据,监听,或者手动改变DOM。咱们能够称为这些为反作用。由于这些操做可能会影响到其余组件或者不能在渲染组件中完成。spa
Effect Hook给函数组件增长了处理反作用的能力。能够理解它的能力和componentDidMount、componentDidUpdate、componentWillUnmount相似。useEffect将这些统一为一个单独的API。 以下是React文档中的例子:插件
import React, { useState, useEffect } from 'react'
function Example() {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = 'good body'
})
return (
<div>
<span>{ count }</span>
<button onClick={()=>setCount(count + 1)}>click me</button>
</div>
)
}
复制代码
当咱们调用useEffect时,就是告诉React在刷新对DOM的更改后执行effect函数。React会在每次渲染后执行effect函数。eslint
effect还能够选择性地指定如何经过返回函数在它们以后“清理”。例如,该组件使用一个效果来订阅朋友的在线状态,并经过取消订阅来清理:code
import React, { useState, useEffect } from 'react'
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null)
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange)
}
})
if(isOnline === null) {
return 'Loading...'
}
return isOnline ? 'Online' : 'Offline'
}
复制代码
在这个例子中,当组件unmount的时候React将会经过ChatAPI取消订阅。在后续的render又将会从新执行这些effect。component
Tip: 咱们在组件中也能够像useState同样屡次调用。
effect在第一次组件挂载和后面组件更新时都会执行,这样就会致使一些非必要的effect重复执行。若是咱们想经过对比先后数据是否发生改变来判断是否触发effect,咱们能够经过传入数组做为第二个参数:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
复制代码
若是你想要执行只运行一次的 effect(仅在组件挂载和卸载时执行),你能够传递一个空数组([])做为第二个参数。这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,因此它永远都不须要重复执行。这并不算是一种特殊状况 —— 依然遵循输入数组的工做方式。
有些场景下,咱们想复用一些关于状态的逻辑。一般会有两种经常使用的解决方案:高阶组件和render Props。自定义Hooks也能够作这些,并且不须要增长更多的组件。
这里有个例子使用useState和useEffect去监听好友是否在线状态。咱们想重用这个监听逻辑在不一样的组件中该怎么作呢?
首先抽象出这个逻辑到一个自定义组件中,叫作useFriendStatus:
import React, {useState, useEffect} from 'react'
function useFriendStatus(frientID) {
const [isOnline, setIsOnline] = useState(null)
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange)
}
})
return isOnline
}
复制代码
如上,传入friendID做为参数,而后返回是否在线。如今咱们看其余组件中如何使用:
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id)
if(isOnline === null) {
return 'Loading...'
}
return isOnline ? 'online' : 'offline'
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
复制代码
这些组件的状态是彻底独立的。钩子是重用有状态逻辑的一种方法,而不是状态自己。事实上,每一个对钩子的调用都有一个彻底独立的状态——因此您甚至能够在一个组件中两次使用相同的自定义钩子。