文章目录
一、简介
组件是 React 的核心、精髓。组件有输入(props)、输出(render)以及自身状态(state)
二、创建
2.1 函数式组件(无状态)
该方式是为了创建纯展示组件,这种组件只负责根据传入的 props 来展示,不涉及到要 state 状态的操作。具体的无状态函数式组件。无状态组件的创建形式使代码的可读性更好,并且减少了大量冗余的代码,精简至只有一个 render 方法,大大的增强了编写一个组件的便利。
// 定义一个 React 组件必不可少的,不管是何种方式定义
import React from 'react';
const App = (props) => {
const { name } = this.props;
return (
<div>Hello, { name }</div>
)
}
export default App;
除此之外,还有以下特点:
组件不会被实例化,整体渲染性能得到提升。
因为组件被精简成一个 render 方法的函数来实现的,由于是无状态组件,所以无状态组件就不会在有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。
组件不能访问 this 对象
无状态组件由于没有实例化过程,所以无法访问组件 this 中的对象,例如:this.ref、this.state 等均不能访问。若想访问就不能使用这种形式来创建组件。
组件无法访问生命周期的方法
因为无状态组件是不需要组件生命周期管理和状态管理,所以底层实现这种形式的组件时是不会实现组件的生命周期方法。所以无状态组件是不能参与组件的各个生命周期管理的。
无状态组件只能访问输入的 props ,同样的 props 会得到同样的渲染结果,不会有副作用
无状态组件被鼓励在大型项目中尽可能以简单的写法来分割原本庞大的组件,未来 React 也会这种面向无状态组件在譬如无意义的检查和内存分配领域进行一系列优化,所以只要有可能,尽量使用无状态组件。
2.2 类组件(有状态)
该方式创建的组件是要被实例化的,并且可以访问组件的生命周期方法
import React from 'react'
class App extends React.Component {
// 该钩子函数用来初始化状态
constructor (props) {
/**
* props 中包含了与父类同样的实例属性和方法
* 子类必须在 constructor 中调用 super 方法,否则新建实例会报错
* 因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法
* 然后再对其进行加工,加上子类自己的势力属性和方法
* 如果不调用 super 方法,子类就得不到 this 对象
*/
super(props)
// 设定初始化状态
this.state = {
title: 'Hello React'
}
}
// 该钩子函数用来渲染出组件的结构
render () {
return (
<div>{ this.state.title }</div>
)
}
}
export default App
其成员函数不会自动绑定 this,需要开发者手动绑定,否则 this 不能获取当前组件实例对象,当然,它有三种手动绑定方法:
// 构造函数中绑定
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
// 使用bind来绑定
<div onClick={this.handleClick.bind(this)}></div>
// 使用箭头函数绑定
<div onClick={ ()=>this.handleClick() }></div>
三、通讯
3.1 逐层通讯
3.1.1 父→子(推荐)
父组件调用子组件的地方,添加了一个自定义的属性,属性的值就是想要传递给子组件的值
<Prolist prolist = { this.state.prolist } />
子组件 ProList 用 this.props 接收数据
import React from 'react';
const Prolist = (props) => {
const { prolist } = this.props;
return (
<div>Hello, { prolist }</div>
)
}
export default Prolist;
3.1.2 子→父
父组件在调用子组件的地方,添加了一个自定义的属性,属性的值为 一个函数,函数内部接收未来子组件传递的数据,父组件可以依据数据做出相应的操作
const getCount = (data) => {
this.setState({
count: data
})
}
render () {
return (
<Prolist getCount = { getCount } />
)
}
子组件中通过 this.props 可以拿到父组件传递过来的所有东西,子组件中通过事件或者 钩子函数给父组件传值, 调用 this.props.自定义的属性名(传递的参数)
import React, { Component } from 'react'
class Com extends Component {
render () {
return (
<div>
<button onClick = { () => {
this.props.getCount( this.state.count )
}}
</div>
)
}
}
3.1.3 路由
3.2 集中式管理(临时)
3.2.1 Node.js Events模块
使用事件订阅,即一个发布者,一个或多个订阅者
首先,安装 event
cnpm install event --save
新建一个 event.js
import { EventEmitter } from 'events';
export default new EventEmitter();
下面列出这个对象的实例方法:
emitter.on(name, fn) // 对事件 name 指定监听函数fN
emitter.addListener(name, fn) // addListener 是 on 方法的别名
emitter.once(name, fn) // 与 on 方法类似,但是监听函数 fn 是一次性的,使用后自动移除
emitter.listeners(name) // 返回一个数组,成员是事件 name 所有监听函数
emitter.removeListener(name, fn) // 移除事件 name 的监听函 fn
emitter.removeAllListeners(name) // 移除事件 name 的所有监听函数
App.js
import React, { Component } from 'react';
import Com1 from "./Com1";
import Com2 from "./Com2";
import "./App.css";
export default class App extends Component{
render(){
return(
<div>
<Com1 />
<Com2 />
</div>
);
}}
Com1.js
import React,{ Component } from "react";
import emitter from "./ev"
export default class Com1 extends Component{
constructor(props) {
super(props);
this.state = {
title: ''
};
}
componentDidMount(){
// 在组件装载完成以后,声明一个自定义事件
this.eventEmitter = emitter.addListener("deliver",(msg)=>{
this.setState({
title: msg
})
})
// 或者用类似于Vue Bus的on
// emitter.on("deliver",(msg)=>{
// this.setState({
// title: msg
// })
// })
}
componentWillUnmount(){
// 组件销毁前移除事件监听
emitter.removeListener(this.eventEmitter);
}
render(){
return(
<div>
{ this.state.title }
</div>
);
}}
Com2.js
import React,{ Component } from "react";import emitter from "./ev"
export default class Com2 extends Component{
constructor (props:) {
super(props)
this.state = {
userName: 'admin'
}
}
setTitle = () => {
emitter.emit("deliver",this.state.userName)
}
render(){
return(
<div>
<button onClick = { setTitle }>点我传值</button>
</div>
);
}}
3.2.2 状态管理
详情请见 Redux