React组件一

组件化开发一

目前,前端三大框架(Vue,React,Angular)都在使用组件化的我形式进行开发。19年最火的跨平台开发技术Flutter也是借鉴了React使用组件化的形式进行开发,甚至移动客户端(iOS和安卓)也都在按照组件化的思想进行架构项目。无论是大前端还是原生开发组件化的思想都是相通的。

组件化的思想

面对一个大的问题时通常的做法是分割成一个个的小问题,每一个小问题又可以当做一个大问题再进行分割处理,简而言之就是分而治之

组件化的思想其实跟数据结构中的树很像,不断的递归之前的分割操作。实际开发中组件的组织形式就是树状结构,如下图

image

这张图是从Vue的官网获取的,但是思想是一样的。

我们的一个项目可以看作是一个大的组件,其中包含各个模块(第二等级大的组件),在包括更小一级的组件等等。

通过组件化的形式分割之后,每一个小组件都是拥有单独功能的模块,并且可重用,可维护。在团队开发中分工明确,效率高等优点。

组件的创建

组件有两种创建方式,类和函数组件。

类组件

类组件使用ES6中的类和继承的特性。

  • 必须继承React.Component

  • 必须实现render方法,返回一个React元素,也就是返回一个JSX语句。

    JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖

import React, { Component } from 'react'
class App extends Component {
  constructor() {
    super();
    this.state = {
      msg: "你好,我是艾佛森"
    };
  }
  render() {
    return (
      <div>
        <h2>我是类组件</h2>
        <span>{this.state.msg}</span>
      </div>
    )
  }
}

constructor构造函数是可选的,可以实现也可以不实现,可以传入props`。

this.state={}用来保存可响应的数据,组件本身的私有数据。

类组件的命名必须是大写字母开头,否则会被React认为是普通的html元素。

函数组件

​ 函数组件定义组件比类组件简便快捷,函数可以接收props属性,返回一个React元素,函数组件的本质就是一个JavaScript函数的调用。

import React from "react"
function Welcome(props) {
  return (
    <div>
        <h2>我是函数组件,打个招呼,{props.name}</h2>
        <span>Hello everyone, I'm Iverson</span>
    </div>
  )
}
  • 函数组件中不能保存自己的状态,不能像类组件中那样能够使用state,但hooks可以使函数组件拥有自己的状态
  • 函数组件没生命周期钩子函数
  • 没有this指针,也就是没有实例对象

不使用ES6创建类组件

​ 需要安装create-react-class依赖,使用命令yarn add create-react-class --save或者npm install create-react-class --save,这种方式作为了解,一般不会用这种方式创建组件。

const createReactClass = require('create-react-class');
const App = createReactClass({
  render: function () {
    return <h1>Hello React</h1>
  }
})

export default App;

组件的生命周期

​ 任何使用都有它的生命周期,从开始有到最后的消亡。每个React类组件都有生命周期方法,可以重写这些方法以便于执行你的业务逻辑。

挂载

​ 当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  • constructor()初始化方法

    • 初始化state数据

    • 绑定事件处理函数

      如果不做上面两个操作没必须要重写构造函数。

      重写时传入props时,尽量调用super(props);可以避免不必要的bug

  • static getDerivedStateFromProps(props, state)不常用

    • 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
  • render()渲染组件

  • componentDidMount组件挂载到DOM中后调用

更新

当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

  • static getDerivedStateFromProps(props, state) 不常用
  • shouldComponentUpdate
    • 根据该方法返回的bool值决定是否渲染,默认情况下state或props数据发生变化时候返回true也即是渲染
  • render()
  • getSnapshotBeforeUpdate在最近一次渲染输出(提交到 DOM 节点)之前调用
    • 此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等
    • 应返回 snapshot 的值(或 null
  • componentDidUpdate
    • props或state更新后会被立即调用,首次渲染不会执行此方法
    • 使用setState更新值的时候,一定要加判断条件,否则可能会导致死循环

卸载

  • componentWillUnmount()会在组件卸载及销毁之前直接调用
    • 在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等
    • 不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它

生命周期图谱如下:


生命周期图

代码验证常用生命周期函数

import React, { Component } from 'react'


class Cpn extends Component {
  render() {
    return <h2>我是Cpn组件</h2>
  }
  componentWillUnmount() {
    console.log("调用了Cpn的componentWillUnmount方法");
  }
}

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      msg: "hello everyone, i'm iversion",
      count: 1,
      isShow: true
    }
    console.log("执行了构造函数。");
  }
  render() {
    console.log("执行了render函数");
    return (
      <div>
        <span>{this.state.msg}</span>
        <h2>{this.state.count}</h2>
        <button onClick={e => { this.setState({ count: this.state.count + 1 }) }}>+1</button>
        <hr />
        <button onClick={e => { this.setState({ isShow: !this.state.isShow }) }}>切换显示</button>
        {this.state.isShow && <Cpn />}
      </div>
    )
  }

  componentDidMount() {
    console.log("执行了componentDidMount方法");
  }

  componentDidUpdate() {
    console.log("执行了componentDidUpdate方法");
  }
}

组件中render函数的返回值

  1. render函数式组件中必须重写的方法。

  2. render函数被调用时会检查this.propsthis.state的状态变化并放回一下类型:

    • React元素 。通过JSX创建的React元素,包括自定义的组件。

    • 数组或 fragments。使得 render 方法可以返回多个元素。通常组件中render方法中只返回一个元素。

      render() {
        return (
          <React.Fragment>
            <ChildA />
            <ChildB />
            <ChildC />
          </React.Fragment>
        );
      }
      
    • Portals。可以渲染子节点到不同的 DOM 子树中。将子节点渲染到存在于父组件以外的 DOM 节点。

    • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点

    • 布尔类型或 null。什么都不渲染。

注意

如果 shouldComponentUpdate() 返回 false,则不会调用 render()

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