React 高阶组件

第一章 引导

image.png

学习之前要有一定的:es6基础、js面向对象编程、react的一些基础知识

第二章 高阶组件介绍

2-1 高阶函数

1、高阶函数的两个基本特征

//1.函数可以做为参数被传递
setTimeout(function(){
  console.log(1)
},1000)

//2.函数可以作为返回值输出
function student(name){
  return function(){
    return name
  }
}

2、应用场景:
1).高阶函数在时间函数的应用

setTimeout()
setInterval()

2).高阶函数在ajax中的应用

$.get('/api/api.json',function(){
    console.log('获取成功')
})

3).高阶函数在数组中的应用

some()
every()
filter()
map()
forEach()
2-2 高阶组件介绍

1、高阶组件基本概念(High Order Component,HOC)
高阶组件就是:接受一个组件作为参数并返回一个新的组件的函数
高阶组件:是一个函数,并不是组件
代码演示地址:https://gitee.com/sunnyfan/react-hight-order-component.git

git clone https://gitee.com/sunnyfan/react-hight-order-component.git
cd react-hight-order-component
npm install
npm start

代码截取

//1.组件A是公共组件,且被定义为一个高阶组件(高阶函数)
import React, {Component} from 'react';
function A(WrappedComponent) {
    return class A extends Component {
        render() {
            return (
                <div className="container">
                    <div className="header">
                        <span>提示</span>
                        <span>X</span>
                    </div>
                    <div className="content">
                        <WrappedComponent></WrappedComponent>
                    </div>
                </div>
            );
        }
    }
}
export default A;

//B组件
import React, {Component} from 'react';
import A from './A';
class B extends Component {
    render() {
        return (
            <div>
                B
            </div>
        );
    }
}
export default A(B);

//C组件
import React, {Component} from 'react';
import A from './A';
class C extends Component {
    render() {
        return (
            <div>
                c
            </div>
        );
    }
}
export default A(C);

应为A组件是公共组件,在B和C组件中都被使用到了,所以可以把A抽离成为公共组件
2、使用场景
多个组件都需要某个相同的功能,使用高阶组件减少重复实现
3、高阶组件实例
react-redux中的connect
export default connect(mapStateToProps,mapDispatchToProps)(Header);

第三章 高阶组价实现

3-1编写高阶组件

1.实现一个普通组件
2.将普通组件使用函数包裹

//第一步:实现一个普通组件
import React, {Component} from 'react';
class A extends Component {
    render() {
        return (
            <div>
                A
            </div>
        );
    }
}
export default A;

//将普通组件使用函数包裹
import React, {Component} from 'react';
function A(WrappedComponent) {
    return class A extends Component {
        render() {
            return (
                <div className="container">
                        <WrappedComponent />
                </div>
            );
        }
    }
}
export default A;
3-1使用高阶组件

1.higherOrderComponent(WrappedComponent);
2.@higherOrderComponent 通过装饰器
要想使用装饰器的用法:那么我们需要对项目进行一些配置
1).开启webpack配置项

在创建的create-react-app项目中 运行 npm run eject

2).安装两个依赖包

npm install babel-preset-stage-2 -D
npm install babel-preset-react-native-stage-0 -D

或者(简写如下):
npm install babel-preset-stage-2  babel-preset-react-native-stage-0  -D

3).项目根目录创建.babelrc配置文件

//.babelrc
{
"presets":["react-native-stage-0/decorator-support"]
}

ps:如果上面出现报错
Cannot find module 'react-native-stage-0/decorator-suppor

npm install metro-react-native-babel-preset -D
将.babelrc改为
{
  "presets": ["module:metro-react-native-babel-preset"],
   "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }]   
  ]
}

配置好后,那么怎么在项目中使用@装饰器来替代写法呢

import React, {Component} from 'react';
import A from './A';

@A  //第二种使用方法:通过装饰器
class B extends Component {
    render() {
        return (
            <div>
                B
            </div>
        );
    }
}

//export default A(B);  第一种使用方法:高阶组件的普通使用
export default B //如果上面使用了@A 那么这个地方直接这样写即可

第四章高阶组件的应用

4-1 高阶组件的代理方式

1、代理方式的高阶组件
返回的新组件类直接继承自React.Component
新组件扮演的角色传入参数组件的一个代理,在新组件的render函数中,将被包裹组件渲染出来,除了高阶组件自己要做的工作,其他功能全局转手给了被包裹的组件

  • 操纵prop
  • 抽离状态
  • 访问ref
  • 包装组件
    1.1.操纵props
    高阶组件是如何向子组件传递参数或者值的呢?
    高阶组件是如何去除组件当中的属性或者值的呢?
import React, {Component} from 'react';
function A(WrappedComponent) {
    return class A extends Component {
        render() {
            const {age, ...otherProps} = this.props
            return (
                <div className="container">
                    <div className="header">
                        <span>提示</span>
                        <span>X</span>
                    </div>
                    <div className="content">
                        <WrappedComponent 
                          name={'张三'} 
                          sex={'男'} 
                          {...otherProps} 
                        />
                    </div>
                </div>
            );
        }
    }
}
export default A;

通过属性值 给子组件传值:age={'18'}
通过结构的方式去除,其他的参数或者属性:

//这样就把age的属性从所有属性值剔除出去了
const {age, ...otherProps} = this.props;
 <WrappedComponent 
    name={'张三'} 
    sex={'男'} 
    {...otherProps} 
/>

1.2.访问ref

//A组件
import React, {Component} from 'react';
function A(WrappedComponent) {
    return class A extends Component {
        componentDidMount() {
            const value = this.refs
            console.log(value.getName())
        }      
        render() {
            const {age, ...otherProps} = this.props
            return (
                <div className="container">
                    <div className="header">
                        <span>提示</span>
                        <span>X</span>
                    </div>
                    <div className="content">
                        <WrappedComponent
                            name={'张三'}
                            sex={'男'}
                            {...otherProps}
                            ref={(value) => this.refs = value}>
                        </WrappedComponent>
                    </div>
                </div>
            );
        }
    }
}
export default A;

//B组件
import React, {Component} from 'react';
import A from './A';

@A
class B extends Component {
    getName() {
        return '我是B组件'
    }

    render() {
        const {name, age, sex} = this.props;
        return (
            <div>
                B
            </div>
        );
    }
}

export default B;

1.3 抽取状态

//A组件
import React, {Component} from 'react';

function A(WrappedComponent) {
    return class A extends Component {
        constructor(props) {
            super(props);
            this.state = {
                inputValue: '张三'
            }
        }

        handleChangeValue = (e) => {
            const value = e.target.value;
            this.setState({
                inputValue: value
            })
        }

        render() {
            const {age, ...otherProps} = this.props;
            const {inputValue} = this.state;
            const newProps = {
                value: inputValue,
                onChange: this.handleChangeValue,
                placeholder: '张三'
            }
            return (
                <div className="container">
                    <div className="header">
                        <span>提示</span>
                        <span>X</span>
                    </div>
                    <div className="content">
                        <WrappedComponent
                            name={'张三'}
                            sex={'男'}
                            {...otherProps}
                            {...newProps}
                        />
                    </div>
                </div>
            )
                ;
        }
    }
}
export default A;

//B组件
import React, {Component} from 'react';
import A from './A';

@A
class B extends Component {
    render() {
        const {age, sex, ...newProps} = this.props;
        return (
            <div>
                <p>
                    <label>请输入我的名字:</label>
                    <input
                        type="text"
                        value={newProps.value}
                        onChange={newProps.onChange}
                        placeholder={newProps.placeholder}
                    />
                </p>
                <p>
                    我的名字:{newProps.value}
                </p>
            </div>
        );
    }
}
export default B;

4-2 继承方式的高阶组件
采用继承关联作为参数的组件和返回的组件,假如传入的组件参数是WrappedComponent,那么返回的组件就直接继承自WrappedComponent
2.1代理方式的高阶组件和继承方式的高阶组件的区别

区别

  • 操作props
  • 操作生命周期函数
//组件D 继承方式的高阶组件
import React from 'react';
const modifyPropsHOC = (WrappedComponent) => class NewComponent extends WrappedComponent {
    componentWillMount() {
        alert('我是在继承生命周期函数')
    }
    render() {
        const element = super.render();
        const newStyle = {
            color: element.type === 'div' ? 'red' : 'green'
        };
        const newProps = {...this.props, style: newStyle};
        return React.cloneElement(element, newProps, element.props.children)
    }
};
export default modifyPropsHOC

//E组件 继承D里面一些
import React, {Component} from 'react';
import D from './D';

@D
class E extends Component {
    componentWillMount() {
        alert('我是原始生命周期函数')
    }
    render() {
        return (
            <div>
                我是div
            </div>
        );
    }
}
export default E;

ps:我们应该“代理方式”优先于“继承方式”的
所以我们在开发过程中,尽量是用代理方式的高阶组件
4-3高阶组件显示名
通过高阶组件中有一个displayName的属性来显示的

import React from 'react';

const modifyPropsHOC = (WrappedComponent) => class NewComponent extends WrappedComponent {
    static displayName = `NewComponent(${getDisplayName(WrappedComponent)})`; //这里设置组件名称

    render() {
        const element = super.render();
        const newStyle = {
            color: element.type === 'div' ? 'red' : 'green'
        };
        const newProps = {...this.props, style: newStyle};
        return React.cloneElement(element, newProps, element.props.children)
    }
};

function getDisplayName(WrappedComponent) {
    return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

export default modifyPropsHOC
效果

第五章 高阶组件的实际应用-底部导航切换

效果图

代码地址

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

推荐阅读更多精彩内容

  • 在目前的前端社区,『推崇组合,不推荐继承(prefer composition than inheritance)...
    Wenliang阅读 77,665评论 16 125
  • 前言 学习react已经有一段时间了,期间在阅读官方文档的基础上也看了不少文章,但感觉对很多东西的理解还是不够深刻...
    Srtian阅读 1,653评论 0 7
  • React进阶之高阶组件 前言 本文代码浅显易懂,思想深入实用。此属于react进阶用法,如果你还不了解react...
    流动码文阅读 1,183评论 0 1
  • title: react-高阶组件date: 2018-07-11 09:42:35tags: web 组件间抽象...
    Kris_lee阅读 25,989评论 2 21
  • 高阶组件是对既有组件进行包装,以增强既有组件的功能。其核心实现是一个无状态组件(函数),接收另一个组件作为参数,然...
    柏丘君阅读 3,060评论 0 6