React 初探(二) - 组件、DOM diff 、setState

概述

当页面中东西很多时,我们需要写大量的 JSX 到我们的 ReactDom.render() 中,这样会造成页面的冗长,所以需要组件来解决这个问题。

组件可以将 UI 拆分成独立的、可复用的部分,并且单独考虑每个部分。组件从概念上看就像是函数,它可以接收任意的输入值(称之为 props),并返回一个需要在页面上展示的 React 元素

写一个组件

在线运行

function component

当有了组件之后,我们便有很多的可能性。demo2在线运行,注意:组件的返回值只能有一个根元素。

function component 嵌套

这里我们使用三个组件,App 组件引用了 Box1Box2 组件。

注意:

  • App 必须只有一个根元素。组件的返回值只能有一个根元素

props 传参

demo在线运行

props 传参

当调用自定义组件时,React 会将 JSX 属性作为对象(props) 传递给该组件。

注意:

  • 组件名称必须以大写字母开头。
  • 组件不能修改自己的 props

React 独到的点:标签就是函数,函数就是对象,标签的属性就是函数的参数。

class component

上述的 demo 在运行的时候发现只要更改一个,另外一个也会进行相应的更改,原因在于两个组件引用了相同的 text,导致一个在改变 text 时,另一个也会改变.不可以通过 props 向两个组件传递 text 的值,因为组件不能修改自己的 props 。那么就需要创建一个作用域,将 text 放进作用域里面,那么将 text 放进函数中是否可以呢?

function component

在实际的运行过程中,却发现更改不了 text 的值,原因在于当更改了 text 的值之后,再次 render,造成了 text 的 init。点击前打开控制台,便可以看到,先 logchange,之后再 loginit,上述主要是 render 的时候 render 了整个 App那么如何做到即有自己的局部变量又可以进行局部 render 呢?这时便需要 class component 来解决了

class component demo

在线运行

class component

注意:

  • class component 必须继承 React.Component
  • constructor 里面必须调用 super()
  • 必须在 constructor 里面初始化 state
  • 必须有 render 函数,并且必须 return 一个标签,并且这个标签只能有一个根元素
  • 无论是 function || class component 都不能更改 props
  • 如果要使用变量需要 this.props.xxx || this.state.xxx
  • 调用函数时可以使用 bind,也可以使用箭头函数,即 onClick = {() => this.onButtonClick}

知道了如何进行 class component 的写法,就可以写出上面的例子了,demo代码在线运行,当使用 class component 的时候,可以有自己的局部变量,并可以进行局部更新

DOM diff

上述的例子中,当点击 change 按钮时,会调用绑定的 onButtonClick 函数,函数中会进行 setState,得到新的 state,新的 state 更新之后会调用 render 函数,render 函数只会更新 span,并且仅仅会更新更改的地方,其他的地方是不会进行更改的。每次 render 都会进行对比,和上一次的结果进行比较,只更改 state 变化的部分,这个找到哪里变化的过程,叫做DOM diff,找两次 render 结果不同之处的过程即是DOM diff

API

setState()

setState(updater[, callback])

关于 setState 需要知道以下几点:

  • setState 是用于更新用户界面以响应事件处理程序( event handle ) 和服务器响应的主要方式 (This is the primary method you use to update the user interface in response to event handlers and server responses.)
  • setState() 视为更新组件的请求而不是立即执行的命令,React 可能会 delay 它,React 不能保证状态更改会立即被应用
  • 因为 setState() 不是立刻更新组件,所以在调用 setState() 之后立即读取 this.state 可能会有问题,所以,要尽可能的使用 componentDidUpdatesetState() 回调,保证在更新被应用之后触发
  • 除非 shouldComponentUpdate() 返回 false,否则 setState() 将始终导致重新渲染,If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
  • 如果需要基于之前的状态设置状态,需要使 setState() 第一个参数是带有 signatureupdater 函数
    (prevState, props) => stateChange
    
    prevState 是之前状态的引用,不能被改变。改变应该通过构建一个基于 prevStateprops 输入的新的对象来进行。例如,假设想要通过 props.step 在状态中增加一个值:
    this.setState((prevState, props) => {
      return {counter: prevState.counter + props.step};
    });
    
    updater 函数接收到的 prevStateprops 保证都是最新的,updater 函数的输出是和 stateshallowly merged
  • setState() 第二个函数时可选的回调函数,在 setState 完成并且组件重新被重新渲染之后被执行一次,通常将 componentDidupdate() 用于此类逻辑
  • setState() 第一个参数也可以也可以使用一个对象,而不是函数
    setState(stateChange[, callback])
    
    这将执行 shallowly merged 到新状态中:
    this.setState({quantity: 2});
    
    这一形式的 setState() 也是异步的,同一周期中多个调用将被合并到一起。例如,如果在相同的周期中尝试多次增加一件物品的数量,其等价于:
    Object.assign(
      previousState,
      {quantity: state.quantity + 1},
      {quantity: state.quantity + 1},
      ...
    )
    
    之后的调用将会重写之前调用的值,因此数量仅会被加一。如果之后的状态依赖于之前的状态,推荐使用 updater 函数形式
    this.setState((state) => {
      return {quantity: state.quantity + 1};
    });
    

优缺点

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

推荐阅读更多精彩内容