组件复用

React组件复用概述

  • 思考:如果两个组件中的部分功能相似或相同,该如何处理?
  • 处理方式:复用相似的功能
  • 复用什么?
    • state
    • 操作state的方法
  • 两种方式:
    • render props模式
    • 高阶组件(HOC)
  • 注意: 这两种方式不是新的API,而是利用React自身特点的编码技巧,演化而成的固定模式

1- render-props模式

  • 思路:将要复用的state和操作state的方法封装到一个组件中
  • 如何拿到该组件中复用的state
    • 在使用组件时,添加一个值为函数的prop,通过函数参数来获取
    • <Component render={(props) =>{}} />
  • 如何渲染到任意的UI
    • 使用该函数的返回值作为要渲染的UI内容
    • <Component render={(props) =>
      <p>{props.attributeA} --- {props.attributeB}</p>
      } />

使用步骤

- 创建Mouse组件,在组件中提供复用的逻辑代码
- 将要复用的状态作为 props.render(state)方法的参数,暴露到组件外部
- 使用props.render() 的返回值作为要渲染的内容

children代替render属性

  • 注意:并不是该模式叫 render props就必须使用名为render的prop,实际上可以使用任意名称的prop
  • 把prop是一个函数并且告诉组件要渲染什么内容的技术叫做: render props模式
  • 推荐:使用childre代替render属性

优化代码

  • 推荐给render props模式添加props校验

  • 移除鼠标事件的监听

    // 添加校验规则

    Mouse.propTypes = {

    children: PropTypes.func.isRequired

    };

    // 在组件卸载时移除事件绑定

    componentWillUnmount() {

    window.removeEventListener('mousemove', this.handleMousMove)

    }

code

// 导入图片资源
import img from './res/img/9d82d158ccbf6c814204fcabbf3eb13533fa4046.gif' /* render props 模式*/
// 创建mouse组件
class Mouse extends React.Component {
// 鼠标位置
state = {
x: 0,
y: 0
};
handleMousMove = (e) =>{
console.log(e);
this.setState({
x: e.clientX,
y: e.clientY
})
};
// 监听鼠标移动事件
componentDidMount() {
window.addEventListener('mousemove', this.handleMousMove)
} // 在组件卸载时移除事件绑定
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMousMove)
} render() {
return this.props.children(this.state)
}
} // 添加校验规则
Mouse.propTypes = {
children: PropTypes.func.isRequired
}; class Show extends React.Component {
render() {
return (
<div>
{/* <Mouse render={(mouse) => {
return <p>鼠标的位置: x: {mouse.x} y:{mouse.y} </p>
}}/>*/}
<h2>render props 模式</h2> {/* children*/}
<Mouse >
{ (mouse) => {
return <p>use children 鼠标的位置: x: {mouse.x} y:{mouse.y} </p>
}}
</Mouse> {/* pic 图片跟随鼠标移动 */}
{/*<Mouse render={(mouse) => {
return <img src={img} alt="pic" style={{position: 'absolute', top: mouse.y - 50, left: mouse.x - 80, width: '200px',}} />
}}/>*/}
<Mouse>
{(mouse) => {
return <img src={img} alt="pic" style={{position: 'absolute', top: mouse.y - 50, left: mouse.x - 80, width: '200px',}} />
}}
</Mouse>
</div>
)
}
} ReactDOM.render(<Show/>, document.getElementById('root'));



2 - 高阶组件 (★★★)

目标

  • 知道高阶组件的作用
  • 能够说出高阶的使用步骤

概述

  • 目的:实现状态逻辑复用
  • 采用 包装模式
  • 手机:获取保护功能
  • 手机壳:提供保护功能
  • 高阶组件就相当于手机壳,通过包装组件,增强组件功能

思路分析

  • 高阶组件(HOC、Higher-Order Component) 是一个函数,接收要包装的组件,返回增强后的组件

    const EnhancedComponent = withHOC(WrappedComponent)
  • 高阶组件内部创建了一个类组件,在这个类组件中提供复用的状态逻辑代码,通过prop将复用的状态传递给被包装组件WrappedComponent

    // 高阶组件内部创建的类组件

    class Mouse extends React.Component {

    render() {

    return (

    <EnhancedComponent {...this.state} />

    )

    }

    }

使用步骤

  • 创建一个函数,名称约定以with开头

  • 指定函数参数,参数应该以大写字母开头

  • 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回

    function withMouse(WrappedComponent){

    class Mouse extends React.Component {}

    return Mouse

    }

  • 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件

  • 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面

    /* 高阶组件*/

    // 导入图片资源

    import img from './res/img/9d82d158ccbf6c814204fcabbf3eb13533fa4046.gif'

    // 创建高阶组件

    function withMouse(WrappedComponent){

    // 该组件提供复用的状态逻辑

    class Mouse extends React.Component {

    // 鼠标状态

    state = {

    x: 0,

    y: 0

    }

    // 控制鼠标状态的逻辑

    handleMouseMove = (e) =>{

    // console.log(e);

    this.setState({

    x: e.clientX,

    y: e.clientY

    })

    };

    // 监听鼠标移动事件

    componentDidMount() {

    window.addEventListener('mousemove', this.handleMouseMove)

    }

          // 在组件卸载时移除事件绑定
    componentWillUnmount() {
    window.removeEventListener('mousemove', this.handleMouseMove)
    }
    render() {
    return <WrappedComponent {...this.state} {...this.props}/>
    }
    } // 设置diaplayName
    Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`;
    return Mouse

    }

    function getDisplayName(WrappedComponent) {

    return WrappedComponent.displayName || WrappedComponent.name || 'Component'

    }

    // 测试组件

    const Position = props => {

    return

    鼠标的位置: x: {props.x} y:{props.y}

    };

    const PicMove = props => (

    <img src={img} alt="pic" style={{position: 'absolute', top: props.y - 50, left: props.x - 80, width: '200px',}} />

    );

    // 获取增强后的组件

    const MousePosition = withMouse(Position);

    // 图片跟随鼠标移动

    const PicPosition = withMouse(PicMove);

    class Show extends React.Component {

    render() {

    return (

    高阶组件

    {/* 渲染高阶组件*/}




          )
    }

    }

    ReactDOM.render(, document.getElementById('root'));

设置displayName

  • 使用高阶组件存在的问题:得到两个组件的名称相同(React默认使用组件的名称为displayname)

  • 原因:默认情况下,React使用组件名称作为displayName

  • 解决方式:为高阶组件设置displayName,便于调试时区分不同的组件

  • displayName的作用:用于设置调试信息(React Developer Tools信息)

  • 设置方式:

    // 设置diaplayName

    Mouse.displayName = WithMouse${getDisplayName(WrappedComponent)};

    function getDisplayName(WrappedComponent) {

    return WrappedComponent.displayName || WrappedComponent.name || 'Component'

    }

传递props

  • 问题:如果没有传递props,会导致props丢失问题

  • 解决方式: 渲染WrappedComponent时,将state和props一起传递给组件

    render() {

    return <WrappedComponent {...this.state} {...this.props}/>

    }

React 组件进阶:

  • 组件通讯是构建React应用必不可少的一环
  • props的灵活性让组件更加强大
  • 状态提升是React组件的常用模式
  • 组件生命周期有助于理解组件的运行过程
  • 钩子函数让开发者可以在特定的时机执行某些功能
  • render props 模式和高阶组件都可以实现组件状态逻辑的复用
  • 组件极简模型: (state,props) => UI

【React -- 5/100】 组件复用的更多相关文章

  1. React组件复用的方式

    React组件复用的方式 现前端的工程化越发重要,虽然使用Ctrl+C与Ctrl+V同样能够完成需求,但是一旦面临修改那就是一项庞大的任务,于是减少代码的拷贝,增加封装复用能力,实现可维护.可复用的代 ...

  2. React -- 3/100 】组件通讯

    通讯 | props | prop-types 组件通讯 Props: 组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props /* class */ .parent-box ...

  3. React jQuery公用组件开发模式及实现

    目前较为流行的react确实有很多优点,例如虚拟dom,单向数据流状态机的思想.还有可复用组件化的思想等等.加上搭配jsx语法和es6,适应之后开发确实快捷很多,值得大家去一试.其实组件化的思想一直在 ...

  4. 函数式编程与React高阶组件

    相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数.这是一个高阶函数,它可以接收函数可以当参数,也 ...

  5. React高阶组件 和 Render Props

    高阶组件 本质 本质是函数,将组件作为接收参数,返回一个新的组件.HOC本身不是React API,是一种基于React组合的特而形成的设计模式. 解决的问题(作用) 一句话概括:功能的复用,减少代码 ...

  6. Svelte入门——Web Components实现跨框架组件复用

    Svelte 是构建 Web 应用程序的一种新方法,推出后一直不温不火,没有继Angular.React和VUE成为第四大框架,但也没有失去热度,无人问津.造成这种情况很重要的一个原因是,Svelte ...

  7. React Native 之 组件化开发

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...

  8. React Native的组件ListView

    React Native的组件ListView类似于iOS中的UITableView和UICollectionView,也就是说React Native的组件ListView既可以实现UITableV ...

  9. 聊聊React高阶组件(Higher-Order Components)

    使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...

随机推荐

  1. PKUWC2020爆零记

    抱歉,这么晚才更. 事实是:我都没有去 所以爆零了 QwQ

  2. windows 安装 Mongodb 数据库及操作图形化软件 Robo 3T

    1 下载系统对应的正确 Mongodb 和 Robo 3T 版本 2 选中 Mongodb 需要安装的路径(后续会使用路径) 3 启动 Mongodb 服务器(到安装相关的路径) 可以参考 菜鸟教程 ...

  3. SQL模糊查询报:ORA-00909:参数个数无效

    用oracle数据库进行模糊查询时,控制台报错如下图所示: 原因是因为敲的太快,语法写错了 正确的写法是 pd.code like concat(concat('%',#{keyword}),'%')

  4. mybatis 注解方式插入,主键由uuid函数生成

    @SelectKey(keyProperty = "record.id", resultType = String.class, before = true, statement ...

  5. Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?

    if first time to install docker, be noted the docker engine started as root copied from: http://blog ...

  6. idea中查看一个类的调用用和被调用用关系

  7. debian ssh/sftp

    检查是否安装了openssh dpkg --get-selections | grep openssh 安装命令 sudo apt-get install openssh-server 安装成功的字样 ...

  8. 宝塔面板修改用户名和密码报错:TypeError: cannot concatenate 'str' and 'NoneType' objects

    [root@dapao~]# bt 14 正在执行(14)... ================================================================== ...

  9. MinGW GCC 9.1 2019年5月3日 出炉啦

    GNU 2019-05-03 发布了 GCC 9.1 https://gcc.gnu.org/onlinedocs/9.1.0/ 有详细的说明MinGW 上可用的 GCC 9.1 版本下载地址 [ m ...

  10. 【Linux 应用编程】文件IO操作 - 常用函数

    Linux 系统中的各种输入输出,设计为"一切皆文件".各种各样的IO统一用文件形式访问. 文件类型及基本操作 Linux 系统的大部分系统资源都以文件形式提供给用户读写.这些文件 ...