此文适合react新手入门,react大佬能够略过(毕竟之前都是写vue,React才写了一个多月, 掩面泪奔)html
主要是学习react中的一些经验总结,若是你以为对你有帮助,能够给个赞github。vue
react项目入门react
react版本:16.0.0 (由于工做中仍是15的版本)git
首先咱们先来讲说 有状态组件和无状态组件github
有状态组件:组件内部状态发生变化,须要state来保存变化。redux
无状态组件:组件内部状态是不变的,用不到state。建议写成函数组件后端
组件设计思路:经过定义少部分有状态组件管理整个应用的状态变化,而且将状态经过props传递给其他无状态组件。 设计模式
有状态组件主要关注处理状态变化的业务逻辑,无状态组件主要关注组件UI渲染工做。这样更有利于组件的复用,组件之间解耦更加完全数组
这样有时就会产生一个问题,若是给UI组件加不一样的逻辑怎么办?bash
2种比较好的方法, this.props.children 和 HOC , 具体实例。那么下面就来详细说说 HOC 高阶组件
知识前置:
装饰器设计模式:容许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是做为现有的类的一个包装。
这种模式建立了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
在JS中高阶函数能够接受一个函数做为参数,返回值做为也是函数的函数。相似的 高阶组件也能够接受一个组件为参数,返回一个被加工过的组件。
本质上高阶函数是一个函数,而不是组件。
例子:
在被包装的组件接收到props以前。高阶组件能够先拦截到props,对props执行增删改等操做,而后将修改过的props传给被包装组件。
import React, { Component } from 'react'
function withPersistentData (wrapedComponent) {
return class extends Component {
componentWillMount() {
let data = localStore.getItem('data');
this.setState({data})
}
render () {
const { data } = this.state;
// 经过{...this.props} 把传给当前组件的值继续传给被包装的组件
return <wrapedComponent data={data} {...this.props} />
}
}
}
@withPersistentData
export default class myComponent extends Component {
render() {
return (
<div>
{this.props.data}
</div>
)
}
}
复制代码
高阶组件经过ref获取被包装的组件实例的引用,而后高阶组件就具有了直接操做被包装组件的属性和方法的能力。
function withRef (wrapedComponent) {
return class extends Component {
someMethod = () => {
// this.wrapedComp 被包装组件实例
// someMethodWrapedComp 被包装组件的方法
this.wrapedComp.someMethodWrapedComp()
}
render () {
// 经过{...this.props} 把传给当前组件的值继续传给被包装的组件
// 给被包装的组件添加ref属性,获取被包装组件实例并赋值给this.wrapedComp
return <wrapedComponent ref={(comp) =>{this.wrapedComp = comp}} {...this.props} />
}
}
}
复制代码
上面已经说过 无状态组件更容易被复用,咱们能够利用高阶组件将本来受控组件中须要本身维护的的状态统一提高到高阶组件中,受控组件无状态化。
import React, { Component } from 'react'
function withControlledComp(wrappedComp) {
state = {
value : null,
}
handleValueChange = (e) => {
this,setState({value: e.target.value})
}
render () {
const newProps ={
controlledProps: {
value: this.state.value,
onChange: this.handleValueChange
}
}
return <wrappedComp {...this.props} {...newProps} />
}
}
@withControlledComp
class ControlledComp extends Component {
render () {
// 此时的受控组件为无状态组件,状态由高阶组件控制
return <input {...this.props.controlledProps} />
}
}
复制代码
function withRedColor (wrapedComponent) {
return class extends Component {
render () {
return (<div style={color: 'red}><wrapedComponent {...this.props} /> </div>) } } } 复制代码
在第一个操做props的例子里,若是要获取key值不肯定时,这个组件就不知足了。
咱们通常采用这种方式:HOC(...params)(wrappedComp)
function withPersistentData = (key) => (wrapedComponent) => {
return class extends Component {
componentWillMount() {
let data = localStore.getItem(key);
this.setState({data})
}
render () {
const { data } = this.state;
// 经过{...this.props} 把传给当前组件的值继续传给被包装的组件
return <wrapedComponent data={data} {...this.props} />
}
}
}
class myComponent extends Component {
render() {
return (
<div>
{this.props.data}
</div>
)
}
}
// 获取key=‘data’的数据
const myComponentWithData = withPersistentData('data')(myComponent)
// 获取key=‘name’的数据
const myComponentWithData = withPersistentData('name')(myComponent)
复制代码
实际上这种形式的高阶组件大量出如今第三方的库中,例如react-redux中的connect函数
connect(mapStateToProps, mapDispatchToProps)(wrappedComponent)
复制代码
挂载阶段
1. constructor
2. componentWillMount
3. render
4. componentDidMount
复制代码
使用场景
1. coustructor
一般用于初始化组件的state以及绑定事件的处理方法(好比bind(this))等
2. componentWiillMound
在组件被挂载到DOM前调用,且只会调用一次,
实际项目中比较少用到,由于能够在该方法中的执行的均可以提到coustructor中
在这个方法中this.setState不会引发从新渲染
3. render
渲染方法。
注意:render只是返回一个UI的描述,真正渲染出页面DOM的工做由react本身完成
4. componentDidMount
在组件被挂载到DOM后调用,且只会调用一次,
一般用于像后端请求数据
在这个方法中this.setState会引发组件的从新渲染
复制代码
更新阶段
1. componentWillReceiveProps
2. shouldComponentUpdate
3. componentWillUpdate
4. render
5. componentDidUpdate
复制代码
使用场景
1. componentWillRceiveProps(nextProps)
这个方法只在props引发组件更新时调用。
通常会比较一下this.props和nextProps来决定是否执行props变化后的逻辑
好比:根据新的props调用this.setState来触发组件的从新渲染
2. shouldComponentUpdate(nextProps,nextState)
这个方法决定组件是否继续执行更新过程。
默认是true,继续更新;false阻止更新。
通常是经过比较nextPops,nextState和当前组件的props,state来决定返回结果。
这个方法能够减小没必要要的渲染,优化组件性能。
缘由:根据渲染流程,首先会判断shouldComponentUpdate是否须要更新。若是须要更新,调用render方法生成新的虚拟DOM与旧的虚拟DOM进行对比(render只是返回一个UI描述),若是对比不一致,则根据最小粒度改变去更新DOM。
3. componentWillUpdate
render前调用,组件更新前执行某些逻辑的地方。
通常不多用到。
4. render
5. componentDidUpdate(prevProps, prevState)
组件更新后被调用,能够做为操做更新后DOM的地方。
这个方法中的prevProps和prevState表明组件中更新前的props和state。
注意:在render前的生命周期中,componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate中的this.state依然指向更新前的state。
复制代码
销毁阶段
componentWillUnmount
组件卸载前被调用。
清除定时器,清除componentDidMount中手动建立的DOM,取消请求等
复制代码
结束语
最后感谢能看到这里的朋友,由于水平有限,若是有错误敬请指正,十分感激。
参考:
react进阶之路