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
也即是渲染
- 根据该方法返回的bool值决定是否渲染,默认情况下state或props数据发生变化时候返回
render()
-
getSnapshotBeforeUpdate
在最近一次渲染输出(提交到 DOM 节点)之前调用- 此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等
- 应返回 snapshot 的值(或
null
)
-
componentDidUpdate
- props或state更新后会被立即调用,首次渲染不会执行此方法
- 使用setState更新值的时候,一定要加判断条件,否则可能会导致死循环
卸载
-
componentWillUnmount()
会在组件卸载及销毁之前直接调用- 在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在
componentDidMount()
中创建的订阅等 -
不应调用
setState()
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它
- 在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在
生命周期图谱如下:
生命周期图
代码验证常用生命周期函数
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函数的返回值
-
render函数式组件中必须重写的方法。
-
当
render
函数被调用时会检查this.props
和this.state
的状态变化并放回一下类型:-
React元素 。通过JSX创建的React元素,包括自定义的组件。
-
数组或 fragments。使得 render 方法可以返回多个元素。通常组件中render方法中只返回一个元素。
render() { return ( <React.Fragment> <ChildA /> <ChildB /> <ChildC /> </React.Fragment> ); }
-
Portals。可以渲染子节点到不同的 DOM 子树中。将子节点渲染到存在于父组件以外的 DOM 节点。
-
字符串或数值类型。它们在 DOM 中会被渲染为文本节点
-
布尔类型或
null
。什么都不渲染。
-
注意
如果
shouldComponentUpdate()
返回 false,则不会调用render()
。