最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

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

来源:懂视网 责编:小采 时间:2020-11-27 20:03:31
文档

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

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

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

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

方法一:切割 render() 方法

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

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

class Panel extends React.Component {
 renderHeading() { // ...
 }

 renderBody() { // ...
 }

 render() { return (
 <div>
 {this.renderHeading()}
 {this.renderBody()}
 </div>
 );
 }
}

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

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

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

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

我们新建了两个单元组件: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 ( <div> <CommentHeading> <Avatar user={...}/>
    
     // Slot for metadata <span>{this.props.metadata}</span> </CommentHeading> <CommentBody/> <CommentFooter> <Timestamp time={...}/>
    
     // Slot for actions <span>{this.props.actions}</span> </CommentFooter> </div>
     ...
     )
     }
    }

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

    class Comment extends React.Component {
     render() { const metadata = this.props.publishTime ? <PublishTime time={this.props.publishTime} /> : <span>Saving...</span>; const actions = []; if (this.props.isSignedIn) {
     actions.push(<LikeAction />);
     actions.push(<ReplyAction />);
     }
     if (this.props.isAuthor) {
     actions.push(<DeleteAction />);
     }
    
     return <CommentTemplate metadata={metadata} actions={actions} />;
     }
    }

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

    比如:

  • 如果 this.props.publishTime 存在,metadata 就是 <PublishTime time={this.props.publishTime} />;

  • 反之则为 <span>Saving...</span>。

  • 如果用户已经登陆,则需要渲染(即actions值为) <LikeAction /> 和 <ReplyAction />;

  • 如果是作者本身,需要渲染的内容就要加入 <DeleteAction />。

  • 方法三:高阶组件

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

    想象这样一个场景:我们想统计页面中所有链接的点击信息。在链接点击时,发送统计请求,同时这条请求需要包含此页面 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 <a> 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 <a> 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 <WrappedComponent {...this.props} />;
     }
     }
     ...
    }

    需要注意的是,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 的思想,我认为非常值得学习。同时,对开发设计的一个建议是,一般情况下,不要犹豫将你的组件拆分的更小、更单一,因为这样能换来强健和复用。

    声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文档

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

    分解React组件的几种进阶方法:React 组件魔力无穷,同时灵活性超强。我们可以在组件的设计上,玩转出很多花样。但是保证组件的Single responsibility principle: 单一原则非常重要,它可以使得我们的组件更简单、更方便维护,更重要的是使得组件更加具有复用性。本文主要和大家分享分解R
    推荐度:
    标签: 方法 分解 的方法
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top