【React】ReactJS序列 组件的key

时间:2016-08-17 20:20:55
作者:zhongxia

概要

使用ReactJs 来构建项目, 已经半年多了,很多知识都是现学现用,从整个项目的脚手架,到项目的打包,发布,并且包含项目的公共样式,公共模块开发, 模块化开发等功能。

虽然已经可以正常的开发项目, 开发组件, 管理公共样式等功能,但是对于 react的 diff算法 和 key之间的关系 没有深入的了解。 只能说大概知道怎么回事,可以运用。

这节文章主要来记录下 React 组件 key 相关的知识

一、问题

在同系列的上一篇博客里,我第一次接触组件key这个概念,因为不理解key的用处及不清楚React组件的更新机制而遇到父级组件调用了render函数而render内的子组件内容不更新的问题。

二、核心内容

React是根据组件上设定的key属性来生成该组件唯一的标识,只有key改变了,React才会更新组件,否则重用该组件。如果想要更新组件内容,请保证每次的key都不一样。

建议大家先看参考文章的:民间文档:进一步阐述和论证,该文档有例子演示也有相应的解决方法。解决方法的核心还是这句话:如果想要更新组件内容,请保证当前组件的key与上一状态组件的key不同。

三、代码示例

1. 静态组件

组件不是动态组件(不需要动态更新)
单纯的展示组件,render之后没有交互操作。
静态组件指定key的时候,可以直接使用 index 或者 不指定【不指定的时候,react会生成一个默认的标识】,保证key不重复即可。

2. 动态组件

组件是动态组件(需要动态更新)
组件除了展示之后, 还有交互操作,比如增加一个节点,删除一个节点等功能。增加和删除节点,是需要刷新组件的,刷新的时候,React内部的Virtual Dom 采用的 diff 算法和 key 又有关系 《留坑,后期补充 diff算法讲解》
刷新的依据是根据key来判断的,相同的key,React采取和上一次刷新的同样方式。

如果这个时候,采用同样的index 来作为key, 然后在列表顶部增加了一个节点, 那么新元素的key 为 0, 和上一次刷新时的旧顶部元素key 相同。此时React将认为这是这个新元素就是就顶部元素,所以就按照顶部元素的内容刷新该元素,导致新元素的内容就是以前的内容,这个和我的预期不一致,我们预期是顶部元素显示新的内容。亲自试一试

添加之前的截图


Paste_Image.png

添加一个节点之后的截图


Paste_Image.png

我希望自己讲得足够清楚,要是不够清楚的话,千万要试一试,不过大概实际开发都是遇到问题再去深入学习的吧,实践越多,遇到的问题越多,就能学到越多。

那么现在我们都知道了,想要组件动态刷新,只要每次刷新都赋予一个新的独一无二的key即可,具体做法有很多种,《民间文档:进一步阐述和论证》,上面提到的文档后面就给出了几种方法,我没试过,大家感兴趣可以去试试。
我的方法,之前查阅资料想了解随机数的生产原理时,看到这么一句话:
逝者如斯夫,时间就是一个随机数。

很有哲理味道的一句话,所以我就采取了时间作为key,那么每次生成的key都是当前时间,是独一无二的,能确保React的动态刷新。代码如下:
上一篇博客的代码

<form className="form-horizontal">
        {this.state.list.map((todo, index) =>
           <Item {...todo}  key={index} />
        )}
 </form>

新的代码,区别在于将 li 标签的key由index换成当前时间

<form className="form-horizontal">
     {this.state.list.map((todo) =>
         <Item {...todo} key={todo.id} />
     )}
</form>

乍一看是没问题的,完美解决问题,但是一运行,结果,你猜。不卖关子了,直接上代码,正确做法是这样的。

key={new Date().getTime() + index}

1月14日更新,+new Date() 等同于 new Date().getTime()

key={+new Date() + index}

哈哈,new Date().getTime()返回了一个精确到毫秒的时间,也就是说,如果是毫秒内的,这个返回值是一样的,也就是key一样,这是React不允许的,直接报错。而恰好你的服务器就是那么快,每个li的生成耗时是毫秒内的,此处的解决方法就是在该基础上index,这样生成的key才是独一无二的。
对比之前方法的优势所在
虽然以前写了下面这个函数能实现动态更新,但是有两个弊端:

componentWillReceiveProps: function(nextProps,nextState) { 
    this.setState({ 
        start_time: nextProps.start_time, 
        end_time: nextProps.end_time, 
        title: nextProps.title 
   }); 
}

一,倒不是代码量的问题,即使以后this.setState说不定会持续增多,但最主要的还是代码维护的问题,若采用了以前的方法,每次state的增减都要去维护componentWillReceiveProps这个方法。

二,以前的方法每次都会更新所有的组件,而有时候你不需要更新所有的组件。例如,在增加一项的时候,你并不需要更新其余项,此时你只需要给新的一样设置新的独一无二的key,而其余项key不变即能实现你的业务逻辑。举个例子吧。

render: function(){ 
    var that = this; 
    return( {   
      this.state.items.map(function(word) { 
          return <Object item={word} key={word.id + ":" + word.order + ":" + (word.color || "")} />; 
      }) } );
 }

核心内容:

key={word.id + ":" + word.order + ":" + (word.color || "")}

可见,只有id,order,color有改变的时候key才会改变,这大概就是key的意义所在吧。

四、其他

那天和公司里面带我写CMS的同事聊天,我记住了两句话:
“我们开始用React也就半年吧,都是现炒现卖。”
“实际工作中现炒现卖会很多,所以学习很重要。”

最近复习周,程序大作业,公司的工作内容,挺忙的,共勉,忙过了会继续更新实践中的感悟。

参考文章

  1. React修炼之路(一)
  2. 官方文档:动态组件key的作用
  3. 民间文档:进一步阐述和论证
  4. loverajoel/jstips:Github上一个每天分享js相关经验的项目

您可能还感兴趣?

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

推荐阅读更多精彩内容