React教程:4 个 useState Hook 示例

摘要: React示例教程。

到 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 (
        <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 可以控制它的调用方式和时间。

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

看看另一个例子:根据前一个值更新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>

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

注意,我们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>
          <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

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

关于Fundebug

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容