Skip to content

Commit 232bcf7

Browse files
Fix : typography grammer mistakes
1 parent a307f8d commit 232bcf7

File tree

1 file changed

+99
-92
lines changed

1 file changed

+99
-92
lines changed
Lines changed: 99 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
---
22
templateKey: "blog-post"
3-
title: "React compound components (Hooks + typescript)"
3+
title: "How to build a simple Compound component using ReactJS hooks"
44
date: 2021-05-25
55
featuredpost: false
66
description: >-
7-
This article talks about what are compound components and how to build an accordion component using the concept of compound components.
7+
This article explains with an example what compound components in react are . How to build a compound component with a tutorial to build accordion.
88
keywords:
9-
- reactjs
10-
- Compound-components
11-
- Hooks
12-
- Typescript
9+
- reactjs
10+
- Compound-components
11+
- Hooks
12+
- Typescript
1313
link: /react-compound-components
1414
category:
15-
- Tutorial
15+
- Tutorial
1616
author: Ashwin kumar
1717
tags:
18-
- react js
19-
- reactjs
20-
- typescript
21-
- compound components
22-
- build accordion component using compound components
18+
- react js
19+
- reactjs
20+
- typescript
21+
- compound components
22+
- build accordion component using compound components
2323
---
2424

25-
**Compound Components** are an advanced and great pattern which you can use to create the meta component. It gives your components more flexibility. It is little difficult to understand the concept initially, But believe me, if you get a hold of it you will love building the components using compound components pattern
25+
**Compound Components** are an advanced and very useful pattern. They can be used to create meta components. They are slightly counter intuitive, but trust me, once you get a hang of it, you will love building components using the compound components pattern.
2626

2727
## What are compound components?
2828

@@ -32,164 +32,165 @@ The compound components are a set of two or more components that work together t
3232
3333
```jsx
3434
<select>
35-
<option>Option1</option>
36-
<option>Option2</option>
37-
<option>Option3</option>
38-
<option>Option4</option>
35+
<option>Option1</option>
36+
<option>Option2</option>
37+
<option>Option3</option>
38+
<option>Option4</option>
3939
</select>
4040
```
4141

4242
In the above example, when you click on an option in the select component, select knows which option you clicked. The select and the option share the state between them and update the selected option state on their own, we don’t need to explicitly configure them.
4343

4444
## Compound Components in Action
4545

46-
In this post, we’ll be building an Accordion component using compound components.
47-
48-
You can check out the [Code sandbox link](https://codesandbox.io/s/interesting-wildflower-wj3iy) for the final demo of the accordion component.
46+
we will build an Accordion component using the compound component pattern.
4947

5048
The accordion component will have four components.
5149

52-
1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component.
50+
1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component.
5351
2. **AccordionItem** - The component that allows us to define each accordion item. Each AccordionItem will have its AccordionButton and AccordionPanel components.
5452
3. **AccordionButton** - The header for the Accordion component.On clicking the accordion button will open the corresponding accordion panel.
5553
4. **AccordionPanel** - The panel for the accordion. This will hold the content of each accordion item.
5654

57-
We are going to create the above mentioned components one by one and also let's see how we can create the link between them.
58-
Let's start with Accordion component. Accordion component will wrap all other necessary components and will maintain the state that is to be shared among all the other components
55+
We are going to create the above mentioned components one by one and also let's see how we can create the link between them.
56+
Let's start with Accordion component. Accordion component will wrap the other components. It will also maintain shared state with other components. In this case the selected accordion item (active item)
5957

6058
```tsx
6159
const Accordion: React.FC<{
62-
children: ReactNode | ReactNode[];
60+
children: ReactNode | ReactNode[]
6361
className?: string
6462
}> = ({ children, className }) => {
65-
const [activeItem, setActiveItem] = useState("");
63+
const [activeItem, setActiveItem] = useState("")
6664
// function to update the active item
67-
const changeActiveItem = useCallback(
68-
(value) => {
69-
if (activeItem !== value) setActiveItem(value);
65+
const changeActiveItem = useCallback(
66+
value => {
67+
if (activeItem !== value) setActiveItem(value)
7068
},
7169
[setActiveItem, activeItem]
72-
);
70+
)
7371

7472
return <div className={className}>{children}</div>
7573
}
76-
```
74+
```
7775

78-
we had created the accordion component, now we need to pass or share the state and the function to update the state to its children. To achieve this, we are going to use the **React Context**. If you are not familiar with React context, please refer [https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html). Iam not gonna explain about react context here, but i will give you a hint about react context.
76+
We have created the root Accordion component. Now we need to pass down or share the state and the update state function with its children. To achieve this, we are going to use the **React Context**. If you are not familiar with React context, please refer [https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html).
7977

8078
> Context provides a way to pass data through the component tree without having to pass props down manually at every level.
8179
8280
Now let's add context to our accordion component.
8381

8482
```tsx
85-
import { createContext, useContext } from "react";
83+
import { createContext, useContext } from "react"
8684

8785
// Creating the context for the Accordion.
8886
export const AccordionContext = createContext<{
89-
activeItem: string;
90-
changeSelectedItem: (item: string) => void;
91-
}>({ activeItem: "", changeSelectedItem: () => {} });
87+
activeItem: string
88+
changeSelectedItem: (item: string) => void
89+
}>({ activeItem: "", changeSelectedItem: () => {} })
9290

9391
export const useAccordionContext = () => {
94-
const context = useContext(AccordionContext);
92+
const context = useContext(AccordionContext)
9593
if (!context) {
96-
throw new Error("Error in creating the context");
94+
throw new Error("Error in creating the context")
9795
}
98-
return context;
99-
};
100-
```
96+
return context
97+
}
98+
```
10199

102-
After creating the context, we need to provide values to the context, it is done by **Context.Provider** element. The values refers to the data that is to be shared among all the components in the accordion. The **Provider** component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers.
100+
Lets provide values to the context using the Context.Provider element. The **Provider** component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers.
103101

104102
```tsx
105103
const Accordion: React.FC<{
106-
children: ReactNode | ReactNode[];
107-
className?: string;
104+
children: ReactNode | ReactNode[]
105+
className?: string
108106
}> = ({ children, className }) => {
109-
const [activeItem, setActiveItem] = useState("");
107+
const [activeItem, setActiveItem] = useState("")
110108

111109
const changeActiveItem = useCallback(
112-
(value) => {
113-
if (activeItem !== value) setActiveItem(value);
110+
value => {
111+
if (activeItem !== value) setActiveItem(value)
114112
},
115113
[setActiveItem, activeItem]
116-
);
114+
)
117115
return (
118116
<AccordionContext.Provider
119117
value={{ activeItem, changeSelectedItem: changeActiveItem }}
120118
>
121119
<div className={`accordion ${className}`}>{children}</div>
122120
</AccordionContext.Provider>
123-
);
124-
};
121+
)
122+
}
125123

126-
export default Accordion;
127-
```
124+
export default Accordion
125+
```
128126

129-
In the accordion, we need to share the activeItem and changeSelectedItem to all the other components, so we are passing those two to the value of accordion context provider. Now We had built the root accordion component and also we have provided the values to the context. Let's build the remaining components and we are going to use the values consumed from the context and make the accordion component work as a whole.
127+
In the accordion, we need to share the activeItem and changeSelectedItem to all the other components, so we are passing them to the context provider which can be obtained using the the useAccordionContext custom hook (which uses the useContext hook internally). Let's build the remaining components. We are going to use the values consumed from the context and make the accordion component work as a whole.
130128

131129
```tsx
132130
// AccordionItem component
133131
export const AccordionItem: React.FC<{
134-
children: ReactNode[];
135-
label: string;
136-
className?: string;
132+
children: ReactNode[]
133+
label: string
134+
className?: string
137135
}> = ({ children, label, className }) => {
138-
const childrenArray = React.Children.toArray(children);
136+
const childrenArray = React.Children.toArray(children)
139137

140138
// label is used to distinguish between each accordion element.
141139
// Adding the label prop to the children of accordionItem along with other props.
142-
const accordionItemChildren = childrenArray.map((child) => {
140+
const accordionItemChildren = childrenArray.map(child => {
143141
if (React.isValidElement(child)) {
144142
return React.cloneElement(child, {
145143
...child.props,
146-
label
147-
});
144+
label,
145+
})
148146
}
149-
return null;
150-
});
151-
return <div className={className}>{accordionItemChildren}</div>;
152-
};
153-
```
147+
return null
148+
})
149+
return <div className={className}>{accordionItemChildren}</div>
150+
}
151+
```
154152

155153
```tsx
156154
// AccordionButton component
157155
export const AccordionButton: React.FC<{
158-
children: ReactNode;
159-
label?: string;
160-
className?:string
156+
children: ReactNode
157+
label?: string
158+
className?: string
161159
}> = ({ label, children, className }) => {
162-
const { changeSelectedItem } = useAccordionContext();
160+
const { changeSelectedItem } = useAccordionContext()
163161
const accordionButtonClickHandler = useCallback(() => {
164-
changeSelectedItem(label || "");
165-
}, [changeSelectedItem, label]);
162+
changeSelectedItem(label || "")
163+
}, [changeSelectedItem, label])
166164

167165
return (
168-
<div onClick={accordionButtonClickHandler} className={`accordion-button ${className}`}>
166+
<div
167+
onClick={accordionButtonClickHandler}
168+
className={`accordion-button ${className}`}
169+
>
169170
{children}
170171
</div>
171-
);
172-
};
173-
```
172+
)
173+
}
174+
```
174175

175176
```tsx
176177
// AccordionPanel component
177178
export const AccordionPanel: React.FC<{
178-
children: ReactNode;
179-
label?: string;
180-
className?:string
179+
children: ReactNode
180+
label?: string
181+
className?: string
181182
}> = ({ children, label, className }) => {
182-
const { activeItem } = useAccordionContext();
183+
const { activeItem } = useAccordionContext()
183184
const panelStyles = [
184185
"accordion-panel",
185186
label === activeItem ? "show-item" : "hide-item",
186-
className
187-
].join(" ");
187+
className,
188+
].join(" ")
189+
190+
return <div className={panelStyles}>{children}</div>
191+
}
192+
```
188193

189-
return <div className={panelStyles}>{children}</div>;
190-
};
191-
```
192-
193194
We have done with creating all other components. Let's see what we have done.
194195

195196
- In the Accordion-item, label prop is used to differentiate between different accordion items. The label prop will be required in the accordionButton and accordionPanel components, so we are adding label prop to the accordionItem children along with the other props.
@@ -204,8 +205,8 @@ import {
204205
Accordion,
205206
AccordionButton,
206207
AccordionItem,
207-
AccordionPanel
208-
} from "./components/accordion";
208+
AccordionPanel,
209+
} from "./components/accordion"
209210

210211
export default function App() {
211212
return (
@@ -238,13 +239,19 @@ export default function App() {
238239
</AccordionItem>
239240
</Accordion>
240241
</div>
241-
);
242+
)
242243
}
243-
```
244+
```
245+
244246
Yayyy!!! We had built the accordion component using the compound components.
245247

246-
We can also build the same accordion component using render props method but there are many limitations to style the inner components (AccordionButton & AccordionPanel) , we need to pass props like renderAccordionButton, buttonClassName for the AccordionButton and we need separate props for AccordionItem and also AccordionPanel.
247-
248-
Look at the accordion component now, it looks clean, you can style each and every component of Accordion using its respective component. In future, if you want to have buttonColour for the AccordionButton component, you can just add that prop to the AccordionButton alone and not to the outer accordion component.
248+
We can also build the same accordion component using render props method. But there are limitations to style the inner components (AccordionButton; AccordionPanel). We will have to pass props like renderAccordionButton for custom button component.
249+
250+
The accordion component, now looks clean. One can style every component of the Accordion using its respective component. In future, if you want to have buttonColour for the AccordionButton component, you can just add that prop to the AccordionButton itself. Not clutter the outer accordion component.
249251

250-
Feel free to try it and check out the component in [code sandbox](https://codesandbox.io/s/interesting-wildflower-wj3iy). I hope you had understood the compound components and how to use them.
252+
<iframe src="https://codesandbox.io/embed/interesting-wildflower-wj3iy?fontsize=14&hidenavigation=1&theme=dark"
253+
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
254+
title="interesting-wildflower-wj3iy"
255+
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
256+
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
257+
></iframe>

0 commit comments

Comments
 (0)