4 个 useState Hook 示例

为了保证的可读性,本文采用意译而非直译。前端

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!react

到 React 16.8 目前为止,若是编写函数组件,而后遇到须要添加状态的状况,我们就必须将组件转换为类组件。git

编写 class Thing extends React.Component,将函数体复制到render()方法中,修复缩进,最后添加须要的状态。github

今天,可使用 Hook 得到相同的功能,并为本身节省了工做时间。在本文中,主要介绍useState hook。数组

useState 作啥子的

useState hook 容许我们向函数组件添加状态,咱们一般称这些为“ hooks”,但它们其实是函数,与 React 16.8 捆绑在一块儿。 经过在函数组件中调用useState,就会建立一个单独的状态。less

在类组件中,state 老是一个对象,能够在该对象上添加保存属性。dom

对于 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

交流

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索