React 16.7.0-alpha hooks 之整體預覽

不懂程式設計發表於2018-11-01

轉載於免費視訊網 www.rails365.net

之前我們介紹了使用hooks的原因,在開始介紹api之前,現在我們先來整體的預覽下這些api。 從上篇的介紹可以知道,Hook是向後相容的,有react開發經驗的你看起來會更順暢。

是一個快節奏的概述。如果你感到困惑,可以看下上面提到的介紹裡的動機:

詳細說明 閱讀動機以瞭解我們為何將Hooks引入React。

State Hook

看下面的例子,他是一個計數器

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)。你可以從事件處理程式或其他位置呼叫此函式。這個函式類似於類中的this.setState,但是它不會將舊狀態和新狀態合併在一起。(我們將在使用State Hook中顯示一個將useStatethis.state進行比較的示例。)

useState的唯一引數是初始狀態。 在上面的例子中,它是0,因為我們的計數器從零開始。請注意,與this.state不同,此處的狀態不必是物件 - 儘管可以是任何你想要的。初始狀態引數僅在第一次渲染期間使用。

宣告多個state

你可以在一個元件中多次使用State Hook

function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}
複製程式碼

陣列解構語法允許我們為通過呼叫useState宣告的狀態變數賦予不同的名稱。這些名稱不是useState API的一部分。相反,React假定如果多次呼叫useState,則在每次渲染期間以相同的順序執行。我們將回到為什麼這種方法有效以及何時有用。

什麼是Hook

鉤子是允許從功能元件(function component)“掛鉤”React狀態和生命週期功能的功能。鉤子在類內部不起作用 - 它們允許你在沒有類的情況下使用React (我們不建議你在一夜之間重寫現有元件,但如果你願意,可以開始在新元件中使用Hook。)

React提供了一些像useState這樣的內建Hook。你還可以建立自定義Hook以在不同元件之間重用有狀態行為。我們先來看看內建的Hooks

詳細說明 你可以在使用State Hook中瞭解更多資訊。

Effect Hook

你之前可能已經從React元件執行資料提取,訂閱或手動更改DOM。我們將這些操作稱為“副作用”(或簡稱為“效果”),因為它們會影響其他元件,並且在渲染過程中無法完成。

Effect Hook中的useEffect增加了在功能元件執行副作用的功能。它與React類中的componentDidMountcomponentDidUpdatecomponentWillUnmount具有相同的用途,但統一為單個API。(我們將在使用Effect Hook時顯示將useEffect與這些方法進行比較的示例。)

例如,下面的元件將在React更新DOM後設定文件標題:

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的更改後(你可以認為是render之後)。 效果在元件內宣告,因此可以訪問其propsstate。預設情況下,React在每次渲染後執行效果 - 包括第一次渲染。 (我們將更多地討論使用effect hook與類生命週期的比較。)

Effects還可以通過指定返回函式來清理他們。看下面的這個例子:

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';
}
複製程式碼

在這個示例中,當元件解除安裝時,以及在由於後續渲染而重新執行效果之前,React將取消訂閱我們的ChatAPI。(如果你願意的話,如果我們傳遞給ChatAPIprops.friend.id沒有改變,有辦法告訴React跳過重新訂閱。)

就像使用useState一樣, 你也可以在元件中使用多個效果:

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允許你通過哪些部分相關(例如新增和刪除訂閱)來組織元件中的副作用,而不是基於生命週期方法強制拆分。

詳細說明 你可以在使用Effect Hook中瞭解更多資訊。

Hooks的規則

鉤子是JavaScript函式,但它們強加了兩個額外的規則:

  • 只能在頂層呼叫Hooks。不要在迴圈,條件或巢狀函式中呼叫Hook
  • 僅從React功能元件呼叫Hooks 不要從常規JavaScript函式中呼叫Hook。 (還有另一個有效的地方叫Hooks - 你自己的定製Hooks。我們馬上就會了解它們。)

詳細說明 你可以在Rules Hook中瞭解更多資訊。

Custom Hooks

有時,我們希望在元件之間重用一些有狀態邏輯的部分。傳統上,這個問題有兩個流行的解決方案:高階元件渲染道具Custom Hooks允許你執行這樣的操作,並且無需向樹中新增更多元件。在上面我們介紹了一個呼叫useStateuseEffect HooksFriendStatus元件來訂閱朋友的線上狀態。假設我們還希望在另一個元件中重用此訂閱邏輯。 首先,我們將這個邏輯提取到一個名為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>
  );
}
複製程式碼

這些元件的狀態是完全獨立的。鉤子是重用有狀態邏輯的一種方式,而不是狀態本身。 事實上,每次呼叫Hook都有一個完全隔離的狀態 - 所以你甚至可以在一個元件中使用相同的自定義Hook兩次。

custom hook更像是一種約定而非功能。如果函式的名稱以use開頭並且它呼叫其他Hook,我們說它是一個Custom HookuseSomething命名約定是linter外掛如何使用Hooks在程式碼中查詢錯誤的。

詳細說明 你可以在Writing Custom 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);
  // ...
}
複製程式碼

詳細說明 你可以在 Hooks API Reference.中瞭解更多資訊。

本文原文件

下一章節state前往此處

相關文章