初識react新功能Hooks

概述
hooks 是一個讓你在不使用類的狀況下還能使用state和別的一些react功能的新功能(React v16.7.0-alpha版本)html

hooks是向後兼容的,這篇文章給有React使用經驗的小夥伴提供了一個概述。react

下面這個例子定義了一個計數器,當點擊按鈕的時候。計數器就會加1數組

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

這上面的例子中useState 就是一個hook,咱們在函數裏面調用它來添加一些局部的狀態。react在從新渲染的時候保存這個狀態值,
useState 返回了一個狀態值(count)和一個能改變狀態值的函數(setCount),你可一再事件或者別的地方來調用這個函數。它除了沒有把新的狀態值和舊的狀態值合併之外別的和class裏面的this.setState()都很類似(這裏有個例子比較useState和this.state()
useState 惟一的參數是初始化的值。就像上面的例子中,初始化的值是0。
注意:和this.state不同、這裏的state你沒必要非得定義成一個對象。固然你也能夠把它定義成一個對象,初始值只會在第一次被渲染的時候用到函數

定義多個狀態變量ui

你能夠在單個組件裏屢次使用State hookthis

function ExampleWithManyStates() {
  // 定義多個state變量
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

數組的解構語法可讓你在調用useState的時候給satate變量定義不一樣的名字,這些名字不是useState API的一部分。相反的,React假設你每一次渲染的時候屢次調用了useState,而每次渲染都是相同的順序執行.咱們會回想一下爲何這樣作,當這對之後有用spa

什麼是Hook
鉤子是容許從功能組件(function component)「掛鉤」React狀態和生命週期功能的功能。鉤子在類內部不起做用 - 它讓你在不依賴類的去狀況下使用React(咱們不推薦你立刻重寫已經存在的組件,可是你能夠嘗試在新的組件裏使用Hook)
React 提供了一些內置的Hooks,好比useState。你也能夠建立本身的Hooks以在不一樣組件中重用插件

Effect Hook
你以前多是從React組件裏執行數據提取,訂閱或手動更改DOM。咱們將這些操做稱爲「函數反作用」(或簡稱爲「效果」),由於它們會影響其餘組件,而且沒法在渲染過程當中完成。
Effect Hook中的useEffect增長了在功能組件函數反作用的功能。它與React類中的componentDidMount,componentDidUpdate和componentWillUnmount具備相同的目的,可是將這些鉤子統一爲單個API。(useEffect與Class鉤子函數比較。code

例如,組件在React更新了Dom後設置了文檔標題component

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // 和componentDidMount ,componentDidUpdate很類似
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

當你調用useEffect,就是在告訴React在刷新DOM後調用你的'effect'函數,Effects 被定義在組建內容, 這樣就能夠訪問到組件的props和state,默認狀況下,React每一次執行render後(包括第一次render)都會執行effects(進一步討論useEffect和Class生命週期的比較
Effects也能夠指定返回函數來清理狀態,下面這個例子,組件使用effect 訂閱了好友的在線狀態,又經過unsubscribing 來清理狀態。(Effects的返回函數至關於componentwillmount)

import { 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';
}

在這個例子裏面,當組件將被卸載以及從新運行effect致使的渲染以前,React會取消對ChatApi的訂閱(若是有須要,在props.friend.id的值沒有改變的狀況下, 咱們能夠告訴React跳太重新訂閱

就像useState同樣, 你能夠在組建中屢次使用effect

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

Hooks容許你經過哪些部分相關(例如添加和刪除訂閱)來組織組件中的函數反作用,而不是基於生命週期方法強制拆分

Hooks的拆分
鉤子是js函數,但它們加入了兩個額外的規則:

  • 只能在頂層調用Hooks。不要在循環語句,條件語句或嵌套函數裏調用Hook
  • 只能React功能組件調用Hooks。 不能從普通JavaScript函數中調用Hook。 (還有一個地方能合法的使用Hooks - 你本身的定製Hooks。)

構建你本身的Hooks
有的時候,咱們但願在組件之間重用一些有狀態邏輯。通常來講,這個問題有兩種流行的解決辦法:高階組件render props。Custom Hooks容許你執行這樣的操做,而且不須要在代碼樹中添加更多組件。
在文章的早些部分,咱們介紹了一個FriendStatus 組件調用useState和useEffect Hooks來訂閱朋友的在線狀態。若是咱們還想要在另外一個組件中重用此訂閱邏輯。
首先,咱們將這個邏輯提取到一個名爲useFriendStatus的自定義Hook中:

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  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>
  );
}

這些組件的狀態是徹底獨立的,Hooks是重用狀態邏輯的一種方式,而不是狀態自己。事實上,每一次Hook調用都是一個徹底單獨的狀態 - 因此你甚至能夠在一個組件中屢次定義一個相同的Hook。
custom hook更像是一種慣例而非功能。若是函數的名字以use開頭而且它調用其餘Hook,咱們就稱它爲一個Custom Hook。useSomething命管理是linter插件如何使用Hooks在代碼中查找錯誤。

Other Hooks
你可能會發現一些不多用的內置Hook頗有用。例如,useContext容許訂閱React上下文而不引入嵌套:

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

useReducer容許使用reducer管理複雜組件的本地狀態:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

下一步
State Hook 文開始吧

相關文章
相關標籤/搜索