惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy International News Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
Cloudbric
Cloudbric
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
N
News and Events Feed by Topic
T
Tenable Blog
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
P
Proofpoint News Feed
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
L
LangChain Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东

逐梦个人博客

使用原生JS监听浏览器的前进后退事件-逐梦个人博客 微信小程序中使用微信头像的实现方式-逐梦个人博客 如何在WebWorker中使用psd.js-逐梦个人博客 如何根据权重裁剪FaceApi.js返回的人脸数据-逐梦个人博客 在WebWorker中使用FaceAPI.js的正确姿势-逐梦个人博客 解锁React组件函数this绑定新方式-逐梦个人博客 关于照片Exif Orientation信息的处理-逐梦个人博客 防止其他网站通过iframe嵌套自己站点的两种方式-逐梦个人博客 警惕!wordpress站长必知的重大安全漏洞合集-逐梦个人博客
React通用带上下文的组件ID实现方案-逐梦个人博客
Dean · 2023-06-15 · via 逐梦个人博客

使用React开发我们会根据需求定义各种组件,然后将组件做一定的组合/嵌套最终实现需求,在这个过程中就会经常出现这么一种情况:

假设现在有CompA,CompB,CompC三个组件,其中CompA和CompB都使用了CompC组件,现需要对CompC中的某个方法做埋点,如何确定该方法是在CompA下调用的,还是在CompB下调用的呢?

可能有些朋友会说可以通过传参来实现,CompA和CompB分别向CompC传递一个参数/标志,这种方式确实可以做到,但是实际使用却并不合理,因为组件的嵌套层级可能很深,如果通过参数一级一级传递,容易出错还不太好维护,仅仅是为了一个简单的埋点参数,有点浪费。有没有什么更好的方法呢?

一、实现

如果CompA下的CompC可获得标识CompA.CompC,CompB下的CompC可获得标识CompB.CompC, 以此类推:CompA.CompC.CompDCompB.CompC.CompD,通过这个标识就可以识别出组件使用的上下文,进而更容易调查问题的根源,现在问题变成了如何让组件自身携带上下文的ID,因为组件的嵌套层级不确定,为了更好的传递这个ID,我的第一反应是使用嵌套的context,大家都知道context允许跨层级传递数据,在一番实验后,得到了以下高阶组件:

import React from 'react';
import PropTypes from 'prop-types';

function WithComponentId(WrappedComponent, definedComponentId) {
  class Component extends React.Component {
    static childContextTypes = {
      componentId: PropTypes.string,
    };

    static contextTypes = {
      componentId: PropTypes.string,
    };

    constructor(props) {
      super(props);

      this.getComponentId = this.getComponentId.bind(this);
    }

    getChildContext() {
      const componentId = this.getComponentId();
      return {
        componentId,
      };
    }

    getComponentId() {
      const componentId = definedComponentId || WrappedComponent.name;
      if (this.context) {
        const { componentId: parentComponentId } = this.context;
        return `${parentComponentId ? parentComponentId : ''}.${componentId ? componentId : ''}`.replace(/(^\.+|\.+$)/g, '');
      }
      return componentId;
    }

    render() {
      return (
        <WrappedComponent {...this.props} getComponentId={this.getComponentId}/>
      )
    }
  }
  return Component;
}

export default WithComponentId;

上面的高阶组件接受上层context传递的组件Id并拼装新的上下文组件ID利用context传递下去,该组件接收一个组件和一个标识ID(可选)作为参数,通过context获取到上层组件的componentId并和当前传入组件的componentId进行组合拼装,得到一个新的带上下文的组件ID并利用context传递给传入组件及其子孙组件,同时向传入组件传递一个getComponentId方法用于获取带上下文的组件ID。

使用的时候仅需用上面的高阶组件包装一下目标组件即可,类似下面:

export default WithComponentId(CompA, 'CompA');
export default WithComponentId(CompB, 'CompB');
export default WithComponentId(CompC, 'CompC');
export default WithComponentId(CompD, 'CompD');

如果不传入组件ID会以传入组件的名称作为组件ID。组件包装完成后,我们就可以在任何通过高阶组件包装了的组件中通过getComponentId方法获取带上下文的组件ID并使用。

二、结语

在上面的高阶组件中,我们选择了使用context来跨层级传递数据,主要是考虑一个大的组件树中有可能部分中间态组件并不需要组件ID,但是我们又需要保证上层组件ID的传递,而且这种方式对于已有项目进行改造是比较合理的,我们只需要通过高阶组件包装我们关心的组件即可,而不需要每个组件都改到,那意味着巨大的工作量。当然对于新项目来说,如果最初的想法就是每个组件都有自己的组件ID,我们也可以在高阶组件中通过属性传值的方式来实现。