相关文章推荐
小胡子的沙发  ·  有没有可能Java ...·  1 周前    · 
谦和的风衣  ·  iOS开发 ...·  1 年前    · 
失恋的柿子  ·  hibernate - Error ...·  1 年前    · 

到 React 16.8 目前为止,如果编写函数组件,然后遇到需要添加状态的情况,咱们就必须将组件转换为类组件。

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

今天,可以使用 Hook 获得相同的功能,并为自己节省了工作时间。在本文中,主要介绍 useState hook。

useState 做啥子的

useState hook 允许咱们向函数组件添加状态,我们通常称这些为“ hooks”,但它们实际上是函数,与 React 16.8 捆绑在一起。 通过在函数组件中调用 useState ,就会创建一个单独的状态。

在类组件中, state 总是一个对象,可以在该对象上添加保存属性。

对于 hooks,state 不必是对象,它可以是你想要的任何类型-数组、数字、布尔值、字符串等等。每次调用 useState 都会创建一个 state 块,其中包含一个值。

示例1:使用 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 (
          {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 可以控制它的调用方式和时间。

示例2:根据之前的状态更新状态

看看另一个例子:根据前一个值更新state的值。

咱们要造个计步器,每点击一次按钮,就计一次,点击完后,它会告诉你你走了多少步。

    import React, { useState } from 'react';
    function StepTracker() {
      const [steps, setSteps] = useState(0);
      function increment() {
        setSteps(steps => steps + 1);
      return (
          总共走了 {steps} 步!
          <button onClick={increment}>
            点点我,步数不是个事!
          </button>
    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>

示例3: 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>
            {items.map(item => (
              <li key={item.id}>{item.value}</li>

注意,我们state初始化为空数组[],并在addItem函数中更新值。

setItems 更新 state 不会将旧值“合并” - 它会使用新值覆盖state。 这与this.setState在类中的工作方式不同。

示例4:具有多个键的 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>
          <label>
            Password:
            <input
              value={form.password}
              name="password"
              type="password"
              onChange={updateField}
          </label>
          <button>Submit</button>
        </form>

如果想试试,可查看 CodeSandbox

首先,我们创建一个state片段,并用一个对象初始化它

    const [form, setValues] = useState({
      username: '',
      password: ''

这看起来像是在类中初始化状态的方式。

还有一个处理提交的函数,其中,e.preventDefault来阻止页面刷新并打印出表单值。

updateField函数更有意思。它使用setValues传递一个对象,为了确保现有的状态不被覆盖,这里使用了展开运算(...form)。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://daveceddia.com/usestate-hook-examples/

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了20亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用