4 個 useState Hook 示例

做者:Dave Ceddiahtml

譯者:前端小智前端

來源:daveceddiareact


阿里雲最近在作活動,低至2折,有興趣能夠看看promotion.aliyun.com/ntms/yunpar…git


爲了保證的可讀性,本文采用意譯而非直譯。github

到 React 16.8 目前爲止,若是編寫函數組件,而後遇到須要添加狀態的狀況,我們就必須將組件轉換爲類組件。數組

編寫 class Thing extends React.Component,將函數體複製到render()方法中,修復縮進,最後添加須要的狀態。less

今天,可使用 Hook 得到相同的功能,併爲本身節省了工做時間。在本文中,主要介紹useState hook。dom

useState 作啥子的

useState hook 容許我們向函數組件添加狀態,咱們一般稱這些爲「 hooks」,但它們其實是函數,與 React 16.8 捆綁在一塊兒。 經過在函數組件中調用useState,就會建立一個單獨的狀態。函數

在類組件中,state 老是一個對象,能夠在該對象上添加保存屬性。工具

對於 hooks,state 沒必要是對象,它能夠是你想要的任何類型-數組、數字、布爾值、字符串等等。每次調用useState都會建立一個state塊,其中包含一個值。

示例:使用 useState 顯示/隱藏組件

這個示例是一個組件,它顯示一些文本,並在末尾顯示一個read more連接,當單擊連接時,它展開剩下的文本。

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

// 兩個 props:
//   text - 顯示的內容
//   maxLength - 在點擊「read more」以前顯示多少個字符
function LessText({ text, maxLength }) {
  // 建立一個狀態,並將其初始化爲「true」
  const [hidden, setHidden] = useState(true);


  if (text <= maxLength) {
    return <span>{text}</span>;
  }

  return (
    <span>
      {hidden ? `${text.substr(0, maxLength).trim()} ...` : text}
      {hidden ? (
        <a onClick={() => setHidden(false)}> read more</a>
      ) : (
        <a onClick={() => setHidden(true)}> read less</a>
      )}
    </span>
  );
}

ReactDOM.render(
  <LessText
    text={`專一、努力是成功的真正關鍵。把你的眼睛盯在目標上,而後朝着目標邁出下一步`}
    maxLength={35}
  />,
  document.querySelector('#root')
);
複製代碼

僅用一行代碼,咱們就使這個函數組件有狀態:

const [hidden, setHidden] = useState(true);
複製代碼

可是這個函數到底在作什麼呢?若是每次渲染都調用它(確實如此),它又是如何保留狀態的。

Hooks 實現的技巧

這裏的「神奇」之處是,React在每一個組件的幕後維護一個對象,而且在這個持久對象中,有一個「狀態單元」數組。當你調用useState時,React將該狀態存儲在下一個可用的單元格中,並遞增數組索引。

假設你的 hooks 老是以相同的順序調用(若是遵循 hooks 的規則,它們將是相同的順序),React可以查找特定useState調用的前一個值。對useState的第一個調用存儲在第一個數組元素中,第二個調用存儲在第二個元素中,依此類推。

這也不是很神奇的事情,主要它依賴於你可能沒有想過的事實:我們寫的的組件是由React調用 ,因此它能夠在調用組件以前事先作好一些工做。 並且,渲染組件的行爲不只僅是函數調用。 像<Thing />這樣的JSX被編譯爲React.createElement(Thing) - 顯然 React 能夠控制它的調用方式和時間。

示例:根據以前的狀態更新狀態

看看另外一個例子:根據前一個值更新state的值。

我們要造個計步器,每點擊一次按鈕,就計一次,點擊完後,它會告訴你你走了多少步。

import React, { useState } from 'react';

function StepTracker() {
  const [steps, setSteps] = useState(0);

  function increment() {
    setSteps(steps => steps + 1);
  }

  return (
    <div>
      總共走了 {steps} 步!
      <br />
      <button onClick={increment}>
        點點我,步數不是個事!
      </button>
    </div>
  );
}

ReactDOM.render(
  <StepTracker />,
  document.querySelector('#root')
);
複製代碼

首先,經過調用useState建立一個新的state,並將其初始化爲0。它返回steps的當前值0setSteps函數來更新 steps,用 increment函數來對steps進行增 1 操做。

這裏還能夠優化的提取increment函數,能夠直接將 increment 函數裏面的內聯到 onClick 裏面:

<button onClick={() => setSteps(steps => steps + 1)}>
  I took another step
</button>
複製代碼

示例:state 做爲數組

記住,state能夠保存任何你想要的值。下面是一個隨機數列表的例子,單擊按鈕將向列表添加一個新的隨機數:

function RandomList() {
  const [items, setItems] = useState([]);

  const addItem = () => {
    setItems([
      ...items,
      {
        id: items.length,
        value: Math.random() * 100
      }
    ]);
  };

  return (
    <>
      <button onClick={addItem}>Add a number</button>
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.value}</li>
        ))}
      </ul>
    </>
  );
}
複製代碼

注意,咱們state初始化爲空數組[],並在addItem函數中更新值。

setItems 更新 state 不會將舊值「合併」 - 它會使用新值覆蓋state。 這與this.setState在類中的工做方式不一樣。

示例:具備多個鍵的 state

再來看看,state爲對象的例子,建立一個包含2個字段的登陸表單:usernamepassword

下面示例主要展現如何在一個state對象中存儲多個值,以及如何更新單個值。

function LoginForm() {
  const [form, setValues] = useState({
    username: '',
    password: ''
  });

  const printValues = e => {
    e.preventDefault();
    console.log(form.username, form.password);
  };

  const updateField = e => {
    setValues({
      ...form,
      [e.target.name]: e.target.value
    });
  };

  return (
    <form onSubmit={printValues}>
      <label>
        Username:
        <input
          value={form.username}
          name="username"
          onChange={updateField}
        />
      </label>
      <br />
      <label>
        Password:
        <input
          value={form.password}
          name="password"
          type="password"
          onChange={updateField}
        />
      </label>
      <br />
      <button>Submit</button>
    </form>
  );
}
複製代碼

若是想試試,可查看 CodeSandbox

首先,咱們建立一個state片斷,並用一個對象初始化它

const [form, setValues] = useState({
  username: '',
  password: ''
})
複製代碼

這看起來像是在類中初始化狀態的方式。

還有一個處理提交的函數,其中,e.preventDefault來阻止頁面刷新並打印出表單值。

updateField函數更有意思。它使用setValues傳遞一個對象,爲了確保現有的狀態不被覆蓋,這裏使用了展開運算(...form)。

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:daveceddia.com/usestate-ho…

交流(歡迎加入羣,羣工做日都會發紅包,互動討論技術)

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

github.com/qq449245884…

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

相關文章
相關標籤/搜索