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

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
O
OpenAI News
AI
AI
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Heimdal Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
S
SegmentFault 最新的问题
宝玉的分享
宝玉的分享
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
TaoSecurity Blog
TaoSecurity Blog
The Cloudflare Blog
V
Visual Studio Blog
Forbes - Security
Forbes - Security
Apple Machine Learning Research
Apple Machine Learning Research
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
The Last Watchdog
The Last Watchdog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
Security Latest
Security Latest
量子位
W
WeLiveSecurity
V
V2EX
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
小众软件
小众软件
The Hacker News
The Hacker News
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
博客园 - 聂微东
T
Troy Hunt's Blog
S
Schneier on Security
有赞技术团队
有赞技术团队
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
P
Privacy International News Feed
Jina AI
Jina AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel The physics behind spring animations - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
React sub-components - The Blog of Maxime Heckel
Maxime Heckel · 2018-02-27 · via Maxime Heckel's Blog

This is the first article in a 3 part series about React Sub-components. Part 2 and Part 3 are available here and here.

Every React project I’ve worked on, whether it was personal or work related, got big enough at some point that their codebase became hard to understand. Every little change required more thinking but lead to a lot of inconsistencies and hacks. Among the many issues I had with such codebases, the lack of reusability of some views was the main one: it lead to a lot of copying/pasting code of complex components/views to ensure they look the same, and the resulting duplicated code didn’t make it easier to maintain nor to test.
Using a sub-component pattern can help to fix all these issues.

What exactly is a sub-component?

For this article, we’ll consider the following view as our main example: a simple Article view to render a title, subtitle, content, metadata and comments of an article object. We’ve all dealt with such views, and they can be really problematic for the reasons stated in the intro.

Example of Article view component

1

class MyArticleView extends React.Component {

5

<div className={css.mainContainer}>

6

<div className={css.wrapper}>

7

<div className={css.titleContainer}>

8

<div className={css.title}>

9

<span>{this.renderTitle()}</span>

11

<div className={css.subtitle}>

12

<div className={css.subtitleBox}> {this.renderSubtitle()}</div>

15

<ul className={css.articlemetadata}>

16

<li className={css.item}>{this.renderAuthor()}</li>

17

<li className={css.item}>{this.renderDate()}</li>

20

<div className={css.contentArticle}>

21

<div className={css.contentTextStyle}>{this.renderMainContent()}</div>

22

<span className={css.inlineComments}>{this.renderComments()}</span>

By using sub-components we can render the same exact view, but with a much more readable code and a reusable component. This is what the result can look like:

Article view component implemented with "sub-components"

1

class MyArticleView extends React.Component {

6

<Article.Title>{this.renderTitle()}</Article.Title>

7

<Article.Subtitle>{this.renderSubtitle()}</Article.Subtitle>

12

<Article.Content>{this.renderContent()}</Article.Content>

13

<Article.Comments>{this.renderComments}</Article.Comments>

In this context, sub-components are defined as components which have their own definition declared within another parent component, and can only be used in the context of that parent component. In the example above, the Title component for instance only exists within the scope of the Article component. It can’t be rendered on its own.
I’m personally not sure about the name, but this is the best term I’ve found to refer to this pattern that I’ve learned to appreciate in my projects.
Sub-components can be seen in multiple libraries such as Recharts or Semantic-UI. The latter refers to sub-components as Modules, Collections and Views in its library, and gives you the ability to render views the same way as stated above.
This kind of pattern is really beneficial:

  • to keep views consistent: you can actually show any kind of data using the Article component above. What matters here is that regardless of its purpose, it will look the same across the whole app.

  • to keep your code tight and clean: Title, Comments, Subtitle, Metadata only make sense within Article and will only be able to be used within it (i.e. where they make sense, since these components are only used in the context of an “Article”).

  • to have easily testable views: for testing such components, Jest and snapshot testing are our allies. It gives us the ability to quickly test any combination of sub-components when using Article. We’ll see how to use Jest to test such a pattern later.

How to build sub-components

In this section we’re going to build the Article component step by step, first by trying to implement the Title sub-component.
The first thing we need in order to build sub-components within a component is a util to find children by “type” or “name” so React will know how to render our Title sub-component. We’ll pass two parameters to this util:

  • children: the list of children of Article

  • component: the component we want to find within the list of children, in our example it will be Title.

Here’s how the util findByType looks like:

1

import React from 'react';

2

const findByType = (children, component) => {

5

const type = [component.displayName] || [component.name];

7

React.Children.forEach(children, (child) => {

9

child && child.type && (child.type.displayName || child.type.name);

10

if (type.includes(childType)) {

17

export default findByType;

Now that we have our findByType util, we can start writing our Article component and the Title sub-component:

Article component with Title sub-component

1

import React, { Component } from 'react';

2

import findByType from './findByType';

3

import css from './somestyle.css';

5

const Title = () => null;

6

class Article extends Component {

9

const { children } = this.props;

11

const title = findByType(children, Title);

17

return <div className={css.title}>{title.props.children}</div>;

21

<div className={css.mainContainer}>

22

<div className={css.wrapper}>

23

<div className={css.titleContainer}>{this.renderTitle()}</div>

31

export default Article;

We now have the ability to use the Article component and its Title sub-component as such:

Usage of the Title sub-component

2

<Article.Title>My Article Title</Article.Title>

In order to extend our set of sub-components, we simply need to instantiate each one of them, write their corresponding render function, and call it in the main render function.
Below you will find the fully implemented component with all its sub-components:

Full implementation of the Article component with all its sub-components

2

import React, { Component } from 'react';

3

import type { Node } from 'react';

4

import findByType from './findByType';

5

import css from './styles.css';

7

const Title = () => null;

8

const Subtitle = () => null;

9

const Metadata = () => null;

10

const Content = () => null;

11

const Comments = () => null;

18

class Article extends Component<Props> {

19

static Title: Function;

20

static Subtitle: Function;

21

static Metadata: Function;

22

static Content: Function;

23

static Comments: Function;

26

const { children } = this.props;

27

const title = findByType(children, Title);

31

return <div className={css.title}>{title.props.children}</div>;

35

const { children } = this.props;

36

const subtitle = findByType(children, Subtitle);

41

<div className={css.subtitle}>

42

<div className={css.subtitleBox}>{subtitle}</div>

48

const { children } = this.props;

49

const metadata = findByType(children, Metadata);

56

<ul className={css.articlemetadata}>

57

{metadata.props.children.map((child) => {

58

return <li className={css.item}>{child}</li>;

64

renderContentAndComment() {

65

const { children } = this.props;

66

const content = findByType(children, Content);

67

const comments = findByType(children, Comment);

74

<div className={css.contentArticle}>

75

<div className={css.contentTextStyle}>{content.props.children}</div>

76

<span className={css.inlineComments}>

77

{comments && comments.props.children}

84

const { children, className, ...rest } = this.props;

87

<div className={css.mainContainer}>

88

<div className={css.wrapper}>

89

<div className={css.titleContainer}>

91

{this.renderSubtitle()}

93

{this.renderMetadata()}

94

{this.renderContentAndComment()}

101

Article.Title = Title;

102

Article.Subtitle = Subtitle;

103

Article.Metadata = Metadata;

104

Article.Content = Content;

105

Article.Comments = Comments;

107

export default Article;

Note: the renderMetadata function is really interesting in this example, it shows how it is possible to use a single render function for two different sub-components.

Using Jest and snapshot testing to test sub-components

Snapshot testing our sub-components is probably the quickest and safest way to make sure that any combination of sub-components within the Article component will render properly. To do this we’re going to use both Jest and Enzyme. Here’s how you can write tests for our example:

Example of snapshot testing sub-components

1

import React from 'react';

2

import { mount } from 'enzyme';

3

import Article from '../';

6

const Content = () => <div>[Mock] Content</div>;

7

const Subtitle = () => <div>[Mock] Subtitle</div>;

8

const Comments = () => <div>[Mock] Comments</div>;

9

const Metadata = () => <div>[Mock] Metadata</div>;

10

const Title = () => <div>[Mock] Title</div>;

11

const Subtitles = () => <div>[Mock] Subtitles</div>;

13

it('Renders with all the sub-components', () => {

15

const component = mount(

35

expect(component).toMatchSnapshot();

38

it('Renders with only the Content and Comments', () => {

40

const component = mount(

50

expect(component).toMatchSnapshot();

53

it('Renders with a Title and without a subtitle', () => {

54

const component = mount(

70

expect(component).toMatchSnapshot();

One last note

While writing this article I noticed that sub-components wouldn’t render on IE 11 and Edge once bundled with Babel 6.26.0 and Webpack 3.10. Maybe it affects other versions, I haven’t checked yet, but all I know is that it only affected the bundled app, it worked fine when the project was running with Webpack Dev Server.

What happened? The culprit here was found when debugging the findByType util. child.type.displayName || child.type.name was returning undefined on IE and Edge for the following reason: “_type_ here is a reference to the component constructor. So if you do _child.type.name_, it references the name property on the constructor -- no supported in IE.

Reference: https://github.com/facebook/react/issues/9803

As a workaround I added a static variable called displayName for each one of my sub-components to ensure that they have a name. Here’s how it should look like on our example:

Sub-components with declared "displayName"

3

const Title = () => null;

4

Title.displayName = 'Title';

6

const Subtitle = () => null;

7

Subtitle.displayName = 'Subtitle';

9

const Metadata = () => null;

10

Metadata.displayName = 'Metadata';

12

const Content = () => null;

13

Content.displayName = 'Content';

15

const Comments = () => null;

16

Comments.displayName = 'Comments';