组件复用

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. sh_02_判断年龄改进版

    sh_02_判断年龄改进版 # 输入用户年龄 age = int(input("请输入年龄:")) # 判断是否满 18 岁 (>=) if age >= 18: # ...

  2. 论文阅读:Stateless Network Functions: Breaking the Tight Coupling of State and Processing

    摘要: 无状态网络功能是一个新的网络功能虚拟化架构,解耦了现有的网络功能设计到无状态处理组件以及数据存储层,在打破紧密耦合的同时,实现了更具可伸缩性和可恢复性的网络功能基础设施.无状态NF处理实例是围 ...

  3. AtCoder AGC002F Leftmost Ball (DP、组合计数)

    题目链接: https://atcoder.jp/contests/agc002/tasks/agc002_f 题解: 讲一下官方题解的做法: 就是求那个图(官方题解里的)的拓扑序个数,设\(dp[i ...

  4. spring cloud:服务网关 Spring Cloud GateWay 入门

    Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使 ...

  5. MyBatis框架之mybatis逆向工程自动生成代码

    http://www.jb51.net/article/82062.htm Mybatis属于半自动ORM,在使用这个框架中,工作量最大的就是书写Mapping的映射文件,由于手动书写很容易出错,我们 ...

  6. 2017年广东省ACM省赛(GDCPC-2017)总结

    今年第一次参加省赛(也是第一次参加这类比赛),既有点惊喜又有点紧张,前一晚没有怎么睡好,有点怕今年打铁,虽然说大一打铁也说的过去,可是谁也不想打铁. 一开始比赛的时候我一开始没有去看题,而是把我们队的 ...

  7. ARM过程调用标准——APCS

    APCS(ARM Procedure Call Standard) 1.ARM寄存器 ARM核支持9种工作模式——User/System/Hyp+/SVC/Abort/Undefined/Monito ...

  8. Text Elements(文本元素)对象

    1.T-Code:SE32 操作路径:主菜单——转到——内文元素——选择内文 2. 清单标题(List heading) 用于定义Report标题名称及描述,如图: 2. 選擇內文 (Selectio ...

  9. 3.k8s资源控制器rs Deployment Job

    k8s资源控制器 #控制器类型 ReplicaSet #rs,确保pod副本数,rs已替代rc Deployment #管理rs,升级.回滚.扩容pod DaemonSet #在每个节点运行一个Pod ...

  10. Spring MVC 中RequestContextHolder获取request和response

    1.最简单方式:处理方法入参 例如: @RequestMapping("/test") @ResponseBody public void saveTest(HttpServlet ...