React中Hooks

1. 前言

Hooks是React16.8版本中的新特性,它能够在不使用class声明的组件中使用state和React特性。react

Tip: React v16.8.0已经支持Hooks。当咱们进行更新时,别忘了更新其余相关依赖包,包括React DOM等。React Native将会在下一个稳定版本支持Hooks。数组

在使用Hooks以前咱们必须知道的几件事:bash

  • Hooks的使用彻底根据咱们的须要进行选择用仍是不用。
  • Hooks是彻底向下兼容。
  • Hooks如今彻底可用,已经发布与v16.8.0。
  • Hooks的出现并无改变咱们以前对react的理解。
  • Hooks的出现并无移除classes的计划。

那么Hooks出现的动机是什么:函数

  • React须要为共享状态提供更好的原生途径。
  • 很难重用组件之间有状态的逻辑。
  • render props和高阶组件会改变组件结构。
  • 复杂的组件变得难以理解。

2. State Hook(useState)

先来介绍第一个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>
    )
}
复制代码

3. Effect Hook (useEffect)

咱们可能执行过请求获取数据,监听,或者手动改变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 中的任何值,因此它永远都不须要重复执行。这并不算是一种特殊状况 —— 依然遵循输入数组的工做方式。

4. 建立自定义Hooks

有些场景下,咱们想复用一些关于状态的逻辑。一般会有两种经常使用的解决方案:高阶组件render Props。自定义Hooks也能够作这些,并且不须要增长更多的组件。

这里有个例子使用useStateuseEffect去监听好友是否在线状态。咱们想重用这个监听逻辑在不一样的组件中该怎么作呢?

首先抽象出这个逻辑到一个自定义组件中,叫作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>
  );
}
复制代码

这些组件的状态是彻底独立的。钩子是重用有状态逻辑的一种方法,而不是状态自己。事实上,每一个对钩子的调用都有一个彻底独立的状态——因此您甚至能够在一个组件中两次使用相同的自定义钩子。

5. Hooks规则

  • Hooks只在顶层调用,不要在循环,条件判断或者嵌套函数中调用钩子。
  • 只在React的函数组件(function Component)中调用Hooks。
  • 对于自定义Hooks,咱们使用use开头命名。
  • eslint-plugin-react-hooks该插件能够规范hooks写法。
  • React 靠的是 Hook 调用的顺序来对应state和useState。
相关文章
相关标签/搜索