分解React组件的几种进阶方法

react 组件魔力无穷,同时灵活性超强。我们可以在组件的设计上,玩转出很多花样。但是保证组件的single responsibility principle: 单一原则非常重要,它可以使得我们的组件更简单、更方便维护,更重要的是使得组件更加具有复用性。本文主要和大家分享分解react 组件的几种进阶方法,希望能帮助到大家。

但是,如何对一个功能复杂且臃肿的 React 组件进行分解,也许并不是一件简单的事情。本文由浅入深,介绍三个分解 React 组件的方法。

方法一:切割 render() 方法

这是一个最容易想到的方法:当一个组件渲染了很多元素时,就需要尝试分离这些元素的渲染逻辑。最迅速的方式就是切割 render() 方法为多个 sub-render 方法。

看下面的例子会更加直观:

class Panel extends React.Component {    renderHeading() {        // ...    }    renderBody() {        // ...    }    render() {        return (            
{this.renderHeading()} {this.renderBody()}
); }}

登录后复制

细心的读者很快就能发现,其实这并没有分解组件本身,该 Panel 组件仍然保持有原先的 state, props, 以及 class 方法。

如何真正地做到减少组件复杂度呢?我们需要创建一些子组件。此时,采用最新版 React 支持并推荐的函数式组件/无状态组件一定会是一个很好的尝试:

const PanelHeader = (props) => (    // ...);const PanelBody = (props) => (    // ...);class Panel extends React.Component {    render() {        return (            
// Nice and explicit about which props are used
); }}

登录后复制

同之前的方式相比,这个微妙的改进是革命性的。

我们新建了两个单元组件:PanelHeader 和 PanelBody。这样带来了测试的便利,我们可以直接分离测试不同的组件。同时,借助于 React 新的算法引擎 React Fiber,两个单元组件在渲染的效率上,乐观地预计会有较大幅度的提升。

方法二:模版化组件

回到问题的起点,为什么一个组件会变的臃肿而复杂呢?其一是渲染元素较多且嵌套,另外就是组件内部变化较多,或者存在多种 configurations 的情况。

此时,我们便可以将组件改造为模版:父组件类似一个模版,只专注于各种 configurations。

还是要举例来说,这样理解起来更加清晰。

比如我们有一个 Comment 组件,这个组件存在多种行为或事件。

同时组件所展现的信息根据用户的身份不同而有所变化:

用户是否是此 comment 的作者;

此 comment 是否被正确保存;

各种权限不同

等等……

都会引起这个组件的不同展示行为。

这时候,与其把所有的逻辑混淆在一起,也许更好的做法是利用 React 可以传递 React element 的特性,我们将 React element 进行组件间传递,这样就更加像一个强大的模版:

class CommentTemplate extends React.Component {    static propTypes = {        // Declare slots as type node        metadata: PropTypes.node,        actions: PropTypes.node,    };    render() {        return (            
// Slot for metadata {this.props.metadata} // Slot for actions {this.props.actions}
... ) }}

登录后复制

此时,我们真正的 Comment 组件组织为:

class Comment extends React.Component {    render() {        const metadata = this.props.publishTime ?         :        Saving...;        const actions = [];        if (this.props.isSignedIn) {            actions.push();            actions.push();        }        if (this.props.isAuthor) {            actions.push();        }        return ;    }}

登录后复制

metadata 和 actions 其实就是在特定情况下需要渲染的 React element。

比如:

如果 this.props.publishTime 存在,metadata 就是 ;

反之则为 Saving…。

如果用户已经登陆,则需要渲染(即actions值为) 和 ;

如果是作者本身,需要渲染的内容就要加入 。

方法三:高阶组件

在实际开发当中,组件经常会被其他需求所污染。

想象这样一个场景:我们想统计页面中所有链接的点击信息。在链接点击时,发送统计请求,同时这条请求需要包含此页面 document 的 id 值。

常见的做法是在 Document 组件的生命周期函数 componentDidMount 和 componentWillUnmount 增加代码逻辑:

class Document extends React.Component {    componentDidMount() {        ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);    }    componentWillUnmount() {        ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);    }    onClick = (e) => {        // Naive check for  elements        if (e.target.tagName === 'A') {             sendAnalytics('link clicked', {                // Specific information to be sent                documentId: this.props.documentId             });        }    };    render() {        // ...    }}

登录后复制

这么做的几个问题在于:

相关组件 Document 除了自身的主要逻辑:显示主页面之外,多了其他统计逻辑;

如果 Document 组件的生命周期函数中,还存在其他逻辑,那么这个组件就会变的更加含糊不合理;

统计逻辑代码无法复用;

组件重构、维护都会变的更加困难。

为了解决这个问题,我们提出了高阶组件这个概念: higher-order components (HOCs)。不去晦涩地解释这个名词,我们来直接看看使用高阶组件如何来重构上面的代码:

function withLinkAnalytics(mapPropsToData, WrappedComponent) {    class LinkAnalyticsWrapper extends React.Component {        componentDidMount() {            ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);        }        componentWillUnmount() {            ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);        }        onClick = (e) => {            // Naive check for  elements            if (e.target.tagName === 'A') {                 const data = mapPropsToData ? mapPropsToData(this.props) : {};                sendAnalytics('link clicked', data);            }        };        render() {            // Simply render the WrappedComponent with all props            return ;        }    }    ...}

登录后复制

需要注意的是,withLinkAnalytics 函数并不会去改变 WrappedComponent 组件本身,更不会去改变 WrappedComponent 组件的行为。而是返回了一个被包裹的新组件。实际用法为:

class Document extends React.Component {    render() {        // ...    }}export default withLinkAnalytics((props) => ({    documentId: props.documentId}), Document);

登录后复制

这样一来,Document 组件仍然只需关心自己该关心的部分,而 withLinkAnalytics 赋予了复用统计逻辑的能力。

高阶组件的存在,完美展示了 React 天生的复合(compositional)能力,在 React 社区当中,react-redux,styled-components,react-intl 等都普遍采用了这个方式。值得一提的是,recompose 类库又利用高阶组件,并发扬光大,做到了“脑洞大开”的事情。

React 及其周边社区的崛起,让函数式编程风靡一时,受到追捧。其中关于 decomposing 和 composing 的思想,我认为非常值得学习。同时,对开发设计的一个建议是,一般情况下,不要犹豫将你的组件拆分的更小、更单一,因为这样能换来强健和复用。

相关推荐:

React组件生命周期实例分析

构建React组件最全方法

store优化React组件的方法详解

以上就是分解React组件的几种进阶方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2786621.html

(0)
上一篇 2025年3月8日 17:47:39
下一篇 2025年3月8日 17:47:44

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • react项目案例总结

    刚刚开始写组件的时候,感觉难度不大(跟vue差不多)。最有意思的应该是jsx语法,个人感觉,jsx的功能性确实比vue的template更强,而且可读性更高. // vue 登录后复制 // jsxhello !{msg} 登录后复制 在j…

    编程技术 2025年3月8日
    200
  • 在项目中使用jest测试react native组件的方法

    目前javascript的测试工具很多,但是针对react的测试策略,facebook推出的reactjs标配测试工具是jest.jest的官网地址:https://facebook.github.io/jest/。我们可以看到jest官网…

    2025年3月8日
    200
  • 用react写一个分页组件的示例

    本文主要和大家介绍用react来写一个分页组件(小结),希望能帮助大家学会用react来写一个分页组件,下面我们一起来学习一下吧。 效果截图(样式可自行修改): 构建项目 create-react-app react-paging-comp…

    2025年3月8日
    200
  • 简单搭建一个react项目

    本文主要和大家介绍了从零开始搭建一个react项目开发,小编觉得挺不错的,希望能帮助大家学习如何搭建一个react项目。 1、npm init 生成 package.json 文件. 2、安装各种需要的依赖: npm install &#8…

    编程技术 2025年3月8日
    200
  • react受控组件与非受控组件详解

    我们都知道,有许多的web组件可以被用户的交互发生改变,比如:,,或者是我现在正在使用的富文本编辑器。这些组件在日常的开发中很不显眼,我们可以很轻易的通过输入一些内容或者设置元素的value属性来改变组件的值。但是,因为react是单向数据…

    编程技术 2025年3月8日
    200
  • React Native自定义控件实现底部抽屉菜单

    原生开发中,自定义view可谓是屡见不鲜的事情,往往系统的控件总不能满足现实的需求。五花八门的产品设计需要我们做出不同的view。关于自定义view的内容网上已经有很多的博文,本篇博客要和大家分享如何在react native中自定义组件实…

    2025年3月8日
    200
  • react前后端同构渲染示例代码

    前后端同构渲染:当客户端请求一个包含react组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互。然后,如果加载组件的过程需要向服务端发出ajax请求等,客户端和服务端又进行了一次交互,这样,耗时相对较长。前后端同构渲…

    2025年3月8日
    200
  • React中的refs的使用教程分享

    ref是react中的一种属性,当render函数返回某个组件的实例时,可以给render中的某个虚拟dom节点添加一个ref属性,如下面的代码所示:     var App = React.createClass({ render: fu…

    2025年3月8日
    200
  • 利用angular、react和vue实现相同的面试题组件

    react 和angular,vue 这三个框架最近都比较火,本文主要给大家介绍的是关于angular、react和vue实现相同的面试题组件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。 面试题要求如下所示 …

    2025年3月8日
    200
  • React拖拽排序组件Dragact详解

    先来一张图看看: Typescript(TS) 最近一直在使用TS进行开发,Eggjs的Ts实践也写了一半。这玩意儿,真的是有毒的,因为能让你上瘾。 随便将一个项目迁移到TS之上,在强大的静态类型检测下,你就能轻松的发现一堆逻辑和边界错误。…

    2025年3月8日
    200

发表回复

登录后才能评论