react中key的另一面用法

当谈起react中key属性,首先且唯一能想到的就是map遍历生成元素时得加上的那么个东西,除此之外key似乎不会用在别的地方了——这是我们对key的印象:它很重要但存在感低。
key是否真的只有这么一个用法?此处按下不表,先来回顾下key的原理及作用:

作用:

key的作用主要是用来减少没必要的diff算法对比,因为对于一个组件或者节点来说,只要父节点状态或者属性发生变化,该组件就会进行diff对比,即使该组件没变化。而如果为组件引入了key值,就可以在diff对比前先做一个校验,如果组件加上了key值,react就会在渲染时对该组件的身份进行校验,首先校验新旧组件的key值是不是一致,不一致的话,该组件直接销毁,然后再新建该组件;如果一致,则比较组件的属性是否发生变化,如果发生变化,则采用diff算法进行对比,然后得出差异对象,如果属性没发生变化,则认为该组件不需要改变。
以上就是key在react中对组件渲染的影响。

运行原理如图:
image.png

再来讲一下背景

以上对key的剖析提到了两个关键词销毁新建,这个特性其实拥有很要紧的作用,在某些特定的场景可以利用到。
为什么会突然关注到key的这个特性?这是因为有一天我在对react官网的基础知识点做”温故而知新“时候的看到有一节讲到了 state 依赖 props 的情况下如何处理

image.png


这个截图官网链接是:https://zh-hans.reactjs.org/docs/react-component.html#constructor
截图中 【避免派生状态的博文】 链接中与本文主角 key 属性相关的地址是 :你可能不需要使用派生 state

它在这里提到了如下观点:

  • 尽量不要使用props派生到state的方式来传递数据

  • 不一定需要派生state:尝试一下 memoization?

  • 万不得已需要派生状态,也不要将this.state放在constructor中,因为constructor只会在生命周期中执行一次,无法响应后续props变化

  • 派生state后需要结合使用 componentWillReceivePropsgetDerivedStateFromProps控制 propsstate的修改,否则组件不随props变化而更新

  • 通过修改key以强制重置组件

官网中讲到了一个state依赖props而出现bug的场景,demo地址:点击查看。我描述如下:当我使用默认的同一个邮箱地址来登录不同的站点,在我编辑一个邮箱后我想切换到另一个站点,发现此时输入框中仍然保留了上次被编辑后的状态。很明显此时我期望的是输入框中应该重置为默认的那个邮箱地址。造成这个问题的原因是从one切换到two后UncontrolledEmailInput组件接收到的props.defaultEmail是一模一样的并没有发生改变,因此也就不会重置state。
官方对这个问题提出了两个解决方案:

  • 一个是将输入组件对其父组件受控,value和change事件都由父组件来传入,避免子组件state与props冲突
  • 另一个就是提到了本文主角使用 key 属性来销毁旧组件的方式

key的解决方案

使用key属性解决方案我将官方demo整理如下:

import React, { Component, Fragment } from "react";
import ReactDom  from "react-dom";
const fakeAccounts = [
  {
    id: 1,
    name: "One",
    email: "fake.email@example.com"
  },
  {
    id: 2,
    name: "Two",
    email: "fake.email@example.com"
  }
];

class UncontrolledEmailInput extends Component {
  state = {
    email: this.props.defaultEmail
  };
  handleChange = event => {
    this.setState({ email: event.target.value });
  };
  render() {
    return (
      <label>
        Email: <input onChange={this.handleChange} value={this.state.email} />
      </label>
    );
  }
}
class AccountsList extends Component {
  state = {
    selectedIndex: 0
  };
  render() {
    const { accounts } = this.props;
    const { selectedIndex } = this.state;
    const selectedAccount = accounts[selectedIndex];
    return (
      <Fragment>
        <h1>
          This demo illustrates resetting an uncontrolled component with a key
        </h1>
        <blockquote>First, make an edit to the account "One" email.</blockquote>
        <UncontrolledEmailInput
          key={selectedAccount.id}      // 关键之处,可删掉它来测试
          defaultEmail={selectedAccount.email}
        />
        <blockquote>Next, select account "Two" below.</blockquote>
        <p>
          Accounts:
          {this.props.accounts.map((account, index) => (
            <label key={account.id}>
              <input
                type="radio"
                name="account"
                checked={selectedIndex === index}
                onChange={() => this.setState({ selectedIndex: index })}
              />{" "}
              {account.name}
            </label>
          ))}
        </p>
      </Fragment>
    );
  }
}
ReactDom.render(
  <AccountsList accounts={fakeAccounts} />,
  document.getElementById("root")
);

它将UncontrolledEmailInput组件添加了key属性,利用key对组件渲染的特殊特性,当切换onetwo按钮时传入到UncontrolledEmailInput组件的key值发生变化,从而每次会销毁然后重建UncontrolledEmailInput组件,因而UncontrolledEmailInput组件中输入框的内容肯定都回到最初。
完美解决!仅仅一个很小的知识点就能解决这个小小的但又棘手的问题

本篇除了key,也让自己回顾了下派生state、不常用的生命周期如getDerivedStateFromPropsUNSAFE_componentWillReceiveProps、受控组件等等一些知识点,每次回顾老的知识点,总发现很多知识又变得生疏了,这还真是个问题啊。

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

推荐阅读更多精彩内容