Mastering React Design Patterns: Create a Collapsible Text
Tags: react, tutorial, typescript, webdev
Published: 2023-12-14 13:58:47

React developers often encounter the challenge of designing components that are both adaptable and reusable. . The Render Props pattern, one of many design patterns available, stands out as a valuable and flexible solution. In this article, we'll delve into the Render Props pattern within the context of a practical example: a collapsible text component featuring a "Show More" functionality.

Imagine you want to create a component that shows a short summary when closed and a more detailed version when opened. Traditional methods might involve complicated prop-passing, but the Render Props pattern provides a neater and more straightforward solution for this.

## The **Render Props Pattern**
The **Render Props pattern** in React involves passing a function as a prop to a component. This function, usually named `render`, handles rendering content and is called within the component. This approach offers a neat and adaptable way to share code and state between components.

## Collapsible Text Component
Let's dive into a practical example using TypeScript and React 18 syntax. Consider a `CollapsibleText` component that takes a `renderText` prop – a function deciding how the text should appear based on the component's state.

```tsx
// CollapsibleText.tsx
import React, { useState } from 'react'

interface CollapsibleTextProps {
  renderText: (isExpanded: boolean) => React.ReactNode
}

export default function CollapsibleText({ renderText }: CollapsibleTextProps) {
  const [isExpanded, setIsExpanded] = useState(false)

  const toggleText = () => {
    setIsExpanded((prevState) => !prevState)
  }

  return (
    <div>
      <div>{renderText(isExpanded)}</div>
      <button onClick={toggleText}>
        {isExpanded ? 'Show Less' : 'Show More'}
      </button>
    </div>
  )
}
```

In this component, the `renderText` function is responsible for determining the text content based on the `isExpanded` state. This encapsulation of rendering logic allows for greater customization.

Now, let's use this component in the parent `App` component:

```tsx
// App.tsx
import CollapsibleText from '@/components/CollapsibleText'

const getTexts = () => {
  const shortText =
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
  const additionalText =
    ' Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'
  const longText = shortText + additionalText

  return { shortText, longText }
}

export default function App() {
  const { shortText, longText } = getTexts()

  return (
    <div>
      <h1>Collapsible Text Example</h1>
      <CollapsibleText
        renderText={(isExpanded) => <p>{isExpanded ? longText : shortText}</p>}
      />
    </div>
  )
}
```
In this simple example, the `getTexts` function generates short and long text content. The `CollapsibleText` component uses the `renderText` prop to decide how the text should be displayed. This approach keeps things clear and easy to manage, even for those new to React.

## Conclusion
With the **Render Props pattern**, React components become more straightforward and adaptable. This guide demonstrated the pattern using a practical example, creating a collapsible text component. By encapsulating rendering logic in a function passed as a prop, components become modular and customizable.

**Github Repo:** https://github.com/JBassx/render-props-demo
**StackBlitz:** https://stackblitz.com/~/github.com/JBassx/render-props-demo

**LinkedIn:** https://www.linkedin.com/in/josephciullo/