react 笔记

  1. react 基本概念解析
  2. react 的组件声明周期
  3. react 高阶组件,context, redux 等高级进阶

特别提醒:

  1. 新版本更新
    React.createClass({ ..... }) 为es5 的写法,新版已经被废弃
    class { ..... } 为 es6 的写法,推荐使用

  2. create-react-app 工程为自动创建新 react 工程的工具项目,该工具包含了打包、 测试、sourceMap、等功能。

  3. react 使用全家桶( react 项目中不可或缺的工具 )
    React 在开发/生产 阶段需要一大堆的工具库辅助开发
    编译:babel
    状态管理工具:redux
    单页应用:react-route

  4. dangerouslySetInnerHTML 用于设置不受保护的HTML
    <div dangerouslySetInnerHTML = {{ __html: this.state.不受保护的代码片段 }}></div>

  5. 好的 React 命名习惯

    • 自定义的组件使用 首字母大写的驼峰命名 (eg: InputComponent..... )
    • 自定义的属性使用 小驼峰命名 ( eg: this.state.getDate..... )
    • 事件尽可能以 handle... 开头命名 (eg: handleChange....)
    • 组件私有的自定方法以下划线 _..... 开头命名 (eg: _getLocalDate...... )
  6. react 概念大全
    事件系统 + 表单应用 + 样式处理 + 组件通讯 + 组件抽象 + 组件性能优化 + 动画 + 自动化测试

一:react 基本概念解析

  1. react 描述 DOM 的 方式 (JSX)jsx 其实就是 JavaScript 对象
  • 在 javascript 中使用类似于 HTML 结构和信息的语法为 JSX 语法。

    很容易转换编译成为 于 HTML 信息的 JavaScript 表示形式( `HTML 的 对象形式` )。
    
    可以根据平台 编译成为 第三方页面 UI 结构
    
jsx编译过程.png
  • ReactDOM 解析
    ReactDOM 是 react 提供的 WEB 页面构建对, 在 移动端 该对象是 ReactApp
    ReactDom 有三个方法:
    findDomNode( this ) // 用于获取页面中的DOM 元素
    UnmountComponentAtNode()
    render() // 用于页面渲染

  • ref 和 findDomNode 获取页面元素辨析
    ref 添加到 Component 上获取的是 Component 实例,
    ref 添加在 原生的 HTML 上获取的是 DOM 节点

        findDomNode 当参数是 DOM 时 就返回一个 DOM( 貌似没什么用 )
        findDomNode 当参数是 Component 时返回 Component 中的 render 中的 DOM
        
        <div>
            <div ref={div => {
                  this._div = div
                 }}>app
            </div>
            <Child ref={child => this._child = child}/>
            <button onClick={()=> {
                        console.log(ReactDOM.findDOMNode(this._div) === this._div);
                        console.log(ReactDOM.findDOMNode(this._child));
                 }}>log refs
            </button>
        </div>
    

    特点
    1. react 使用 jsx 描述 DOM / UI 结构
    2. jsx 预防在编译阶段 会转换为 DOM 的 JavaScript 表现形式
    3. ReactDom 对象只有一个作用 ---> 负责将 JavaScript 对象 渲染成为 真正的页面 DOM
    4. 在渲染过程中 react-dom( web ) ,react-canvas( canvas ) ,react-app (react-native) 可分别将该 JS 对象渲染到不同的平台上

  1. render 函数中都可以写什么

render 函数能且只能 返回一个 jsx 对象, 就是必须 返回一个值,并且这个值 是一个 类似于 DOM 的 jsx 语法

  • jsx 结构中可以使用 { } ( 大括号 ) 插入 表达式

    { } 大括号中 可以放置任何表达式内容( 包括 函数,jsx 结构,变量,对象,表达计算式 )

      ...
      render () {
          const isGoodWord = true
          return (
                      <div>
                            React 小书
                            {
                                // jsx 中的注释 只能写在 大括号中
                                // 下面表示一个三目表达式
                                // 这里不能写 JavaScript 的 多行表达式
                                isGoodWord ? <strong> is good</strong> : <span> is not good</span> 
                            }
                            {
                                  // 下面表示一个自执行函数,函数中可以做任何你想做的事,也可以有多行代码
                                 (function() {
                                           .... doSomething
                                 })
                            }
                      </div>
                  )
      }
      ...
    
  • jsx 结构中的 null 表示什么都不显示,相当于忽略了该表达式的插入,可以使用这个特性来 隐藏元素

  • jsx 结构整体当做变量用于 参数传递或者使用

    jsx 语法其实就是一个个 js 的对象,所以可以使用任何变量能使用的方式传递或者使用它们

     ...
      render () {
          const isGoodWord = true
          const goodWord = <strong> is good</strong>    // 这是一个 jsx 变量
          const badWord = <span> is not good</span>   // jsx 变量还可以当做 函数参数传递
          return (
              <div>
                    React 小书
                    {isGoodWord ? goodWord : badWord}
              </div>
         )
      }
      ...
    
  • 在 render 的 {} 中 可以使用 map 等 返回 DOM LIST 的函数方法

      // 必须返回一个 表示 DOM LIST 
     const arr = [1, 2, 3, 4, 5];
     render () {
          return (
                <select>
                      this.arr.map((item) => 
                          <option>item</option>
                      )
                </select>
            )
      }
      ...
    
  • jsx 中的 三元表达式 其实就是一句完整的表达式,所以可以被 识别

  1. jsx 语法中 注释的写法

    注释只能写在 JavaScript 表达体 中( 即只能 写在 { } 大括号中 ),写在 大括号外面的注释不被识别
    要是真的想写注释,可以给某个或者某条语句外面添加一个 大括号,然后在进行注释

  2. 组件嵌套

组件和组件之间可以 嵌套使用。但是所有的自定义组件都必须是以 大写字母开头的组件。

  1. 事件系统

    • 每个 jsx 元素上面都可以自己定义 on* 类型的事件监听函数,只能用在普通的 html 元素标签上,不能使用在自定义的元素标签上

    • 每个事件监听函数 都有一个默认的 event 对象。一个经过 react 包装的 event 对象

    • react 的事件代理机制
      react 将事件处理函数统一绑定在最外层上面
      react 对于原生的 DOM 节点可以书写原生的事件
      ** 特别注意 **: 因为 react 的事件代理机制,注意 stopPropagation() 阻止事件冒泡的时机

    • 注意 每个 事件监听函数 若内部有使用到 this 的情况,需要在声明函数的地方,动态的绑定 this

      // bind this 的时候 可以 传递默认的 参数
      render () {
          return (
              <h1 onClick={this.handleClickOnTitle.bind(this, 'Hello')}>React 小书</h1>
          )
      }
      
    • react 的 this 自动绑定区域
      A. class 内部自动绑定 this ( class 的 { } 大括号这一层级 自动绑定 this )
      B. 构造函数 constructor 中没有自动绑定this
      C. 箭头函数自动绑定this
      D. 使用 bind 显示绑定 this

  2. state 的 使用

    • 每次调用 setState 都会触发 react 的重新渲染,并且重新调用 render 方法 **
  • setState 函数执行时可以接受一个参数(prevState)
  • 多个 setState 执行需要合并时 需要 prevState 参数的帮忙。并且 react 会将 多个 setState 操作合并为一个最终的状态进行一次性渲染
  • react 自己的 diff 算法保证只会渲染更改的地方
  1. props 的使用
  • props 带来更好的复用性和 可配置性

  • defaultProps设置组件默认的 props, 和 this.props 获取配置参数,设定 组件的默认 props 数据

  • 组件内部一旦传递进 props 不可以在组件内部更改 props
    但是 组件内部 可以获取 props. 将其赋予 state 或者 其他变量进行数据的增删改。

组件的生命周期


  1. 前端的状态数据管理, - 状态提升

将组件之间共享的数据抽象并提取出来放到最近的 公共父节点上,然后通过 props 将数据传递给子组件, 这样就是一个状态数据的提升。

那么问题来了? 怎样管理 多个层次的组件 所依赖的状态呢 ?
( ** 请大家关注 context 和 redux 的相关内容 ** )

  1. 组件的基础生命周期
组件声明周期过程.png

react 将组件渲染 并塞到 DOM 元素中然后绘画在页面上的过程称为组件的挂载

所以 由挂载的过程你可以很好的理解下面的组件处理过程

constructor() // 初始化状态数据
componentWillMount() // 组件的挂载过程
render()
// 构造 DOM 元素 插入页面
componentDidMount() // 组件的挂载过程
。。。。。
// 即将从页面中删除元素
componentWillUnmount()
// 从页面中删除元素

以上 的几个生命周期 都是 组件的 第一阶段的状态管理函数

  • 一般的 getDefaultProps 和 getInitialState 都会放在 constructor 中完成
  • 组件的隐藏 会触发 页面的 componentWillUnmount() 函数,所以,在页面被隐藏时要注意剩余数据 的处理。
  • componentWillMount() 函数多用于组件的启动,eg: ajax, localStore数据的拉取,定时器的启动,等工作。
  • componentDidMount() 函数用于依赖 DOM 的事件动作或者其他。eg: 动画的启动需要依赖 DOM. componentWillMount 的时候 DOM 还没有挂载完成,所以动画的启动需要放在 DidMount 函数中完成
  1. 组件更新的生命周期

    shouldComponentUpdate(nextProps, nextState) 返回一个 boolean 数据。 用于控制组件是否 重新渲染。
    componentWillReceiveProps(nextProps). 多用于处理父组件传递过来的 props
    componentWillUpdate(); 组件开始更新之前调用。
    componentDidUpdate(); 组件更新并且重新渲染到 DOM 之后调用。

  2. ref 的作用

ref 属性用于获取已经挂载的 DOM 节点( 类似于为元素添加 id 属性,用于表示元素 )
refs 用于引用已经 标识的 DOM 节点,获取其 对象的 属性 和 方法

** 注意: ** 多余 的 DOM 操作 会产生代码的噪音,不推荐大量使用 ref 操作 DOM

ref 版本改动:标识 DOM 节点的 ref由原来的字符串改为一个回调函数
旧版本 <input ref="myinput" />
新版本 <input ref={(input)=>{this.myinput=input;}}/> 可以额外有一个参数 参数有妙用

  1. props.children 和 自定义标签元素中 添加 额外的 HTML DOM 元素

普通的标签元素中内嵌的 DOM 元素可以直接添加。但是自定义标签组件怎讲将内嵌的 DOM 内容传递到下一层呢?

我们使用 props.children 可以获取到上层的 自定义标签中的内嵌的 DOM 元素

  1. jsx 中任何的 html 格式的 代码都会被转义掉,为了防止 xss 攻击

    为了显示 带有 html 标签的元素我们需要用到元素的 dangerouslySetInnerHTML (
    这个只是元素的一个属性

    .....
    render() {
          renturn (
             <div
                    className="edit-html"
                     // 按照下面的方法设置元素的 html 的内容
                    dangerouslySetInnerHtml={ { __html: this.state.content } }
             >
        ) 
    }
    .....
    
  2. propsTypes 和 组件的参数验证
    JavaScript 是弱类型的语言,但是为了 ** 防止和校验上一层传递过来数据的正确性,我们使用 PropTypes 来做数据类型的校验相当于为数据添加数据类型,强类型的数据 **

     import React, { Component, PropTypes } from 'react'
     ....
     class ChildComponent extends Component {
           // 下面这些是固定的 书写格式
           static propsTypes = {
                 parentAttr: PropTypes. object,
                 parentArr: PropTypes.array
           }
           .........
     }
     ......
    
  3. 高阶组件就是一个函数,你传递给他一个组件对象,他返回给你一个经过包装的组件对象
    ** 相当于在原始组件之上 添加了一层经过封装的父组件 ** 功能性的封装

    ** 作用:**

    • 组件状态提升
      将子组件需要操作的数据交给父组件来管理,然后通过 props 向下传递数据。此为 状态提升
      当某个数据/状态 被多个组件依赖/使用 时,应该通过状态提升来管理

    • 高阶组件本质就是为了组件之间的复用,将重复的代码 操作放在高阶组件中,下面的基本组件就可以复用了

       比如数据的 ajax 的读取,事件的统一操作等
      
    • 高阶组件中 通过 props 传递数据

    • 高阶组件可以很好的实现 Smart 组件( 依赖数据操作的组件/ 高阶组件 ) 和 Dumb 组件( 只需要上层数据props的纯组件 ) 的分离

      Smart 组件和 Dumb 组件( 或者说高阶组件 )的出现,很好的实现了 react 的 mvc 结构,达到了高层次的 组件的复用。

高阶组件知识点
1. 高阶组件 本质就是一种 组件的 mixin 模式
1. es7 的装饰着模式可以用来扩展高阶组件
2. 一个 Smart 组件可以被多个高阶组件装饰,并且按照顺序执行

高阶组件.png
  1. react 的 context 作为全局的对象,有自己独特的写法

    ** context 必须和 propType 强制数据类型 共同使用 **

    • 强制数据类型
      import React, { Component, PropTypes } from 'react'
      ......
      static propsTypes = {
      themeColor: PropTypes. string
      }

    • 定义context 时的写法

      import React, { Component, PropTypes } from 'react'
      ....
      class ParentComponent extends Component {
          // 下面这些是固定的 书写格式
          static propsTypes = {
                themeColor: PropTypes. string
          }
          .........
          // 这里设置了 本组件包括其 所有子组件的 context 
          getChildContext () {
                 return { themeColor: this.state.themeColor }
          }
      }
      ......
      

    context 在定义时,必须有两个步骤
    声明属性的数据类型
    设置获取全局 Context 的方法 getChildContext

    • 使用 context

            import React, { Component, PropTypes } from 'react'
            ....
            class ChildComponent extends Component {
                  static propsTypes = {
                        themeColor: PropTypes. string
                   }
                  render () {
                          return (
                                <div  style={{ color: this.context.themeColor }}>context 的获取使用地方</div>
                          )
                   }
            }
      

    context 在使用时必须有两个步骤
    声明要使用的 context 数据类型
    使用 this.context.属性 获取属性的值

context 使用步骤繁杂是有原因的
1. context 作为全局拥有的对象,必须保证其数据的正确性。
2. react 官方不推荐使用 context, 进而希望大家能够使用更为友好的 Redux, Mobx等

React 组件进阶


  1. react 理念分析

    • React 的组件本质是创建了一个对象,由框架本身添加了 10 个声明周期函数( 其实就是普通的函数,只是有执行顺序、触发时机、优化处理等特点 )
      具体参见 React 的最初写法 React.createClass({ .... }), 中间是一个对象

    • 声明周期函数,就是对象中的普通函数
      传值 + 操作处理 + 返回值

    • react 特点:
      1. 简洁: 足够的简洁,其本身只有自己的 api
      2. 非声明式的单项数据绑定
      3. ** 面向 HTML5, 专注视图层操作 ** 将 JavaScript 和 HTML5 整合在一起。
      4. 高性能的密集 DOM 操作
      5. 支持后端渲染。
      6. 跨平台,一种书写,能够编译出多种结果 ** ReactNative **

      react 函数式编程 ( 小函数编程 )
      1. 尽可能抽象出公共使用的小函数。
      2. 在一个庞杂的 逻辑体 中能够提取出 功能小函数

    • 组件化
      狭义的组件化:ui组件 ---> 具体的组件( Tabs 组件 / Dropdown 组件 )
      广义的组件化: 业务数据 + UI 组件的组合使用

      组件化的发展进程

      DOM操作为主( 根据逻辑改变 DOM 结构 ) --> MVC( 数据和界面解耦 ) --> 小组件( 数据 + 界面 + 样式的结合体 eg: angular 指令 ) ----> HTML5 的引入 ( javascript + HTML + css 合为一体)

      HTML Templetes --> custom Element --> shadow DOM --> HTML Imports

    • ** 非常重要:**
      ** 组件封装的进程其实就是面向对象的思想逐步成熟** (通过实例化的方法制造对象

      一个组件的对象实例: ( 基本的封装性 + 简单的声明周期 + 明确的数据流动 )

  2. 表单组件

    表单组件分为受控组件和非受控组件
    受控组件:依靠 state 和内部事件 改变状态的组件,有很强的耦合性,复用性不高

       非受控组件,通过 defaultProps, props 传值的组件,复用性好
               非受控组件可以通过 事件和 ref 向上传递数据
    
  3. 组件通讯 ---> 事件订阅
    EventEmitter

  4. 组件性能优化

    1. 引入纯函数( pureRender 函数或者 Smart组件 )

    2. 使用 数据对比决定 纯函数组件是否渲染 shouldComponentUpdate()

    3. 引入不可变对象 或者 es6 对象扩展 进行数据对比

         Immutable 不可变对象,对 Immutable 对象的 增 删 改 都会生成一个新对象,类似于对象的深拷贝,但是比对象的深拷贝效率要高
      
         es6 对象扩展 和 对象/数组的解构赋值,也能够得到一个新的对象
      
    4. Immutable 解析

      ** Immutable 可以提供一种全新的数据对比和生成形式,类似于 es6 的对象扩展 和 解构赋值 **

         Immutable 三种数据类型 
         Map: 对应于 `Object`, 键值对集合
         List :   对应于 `Array` 有序的重复列表
         ArrayList: 无序不可重复的列表
      
         // 特性应用实例
         import { Map, List, Arraylist } from 'immutable'
         ....
         this.setSatate({
                 data: Map({ times: 0 })      // 得到一个新的 Immutable 对象
         })
      

      Immutable 方法应用实例 ( Immutable.is 可以用来进行比较,比 === 全等的效率高 )

         import { is } from 'immutable'
         .....
         shouldComponentUpdate(nextProps, nextState) {
               if( is( nextProps.attr, nextState.attr ) )
                     return false;
              ......
         }
      

.

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

推荐阅读更多精彩内容