Learning React for the first time can be unnecessarily difficult. Like, seriously - how can React, a JavaScript UI library be such a challenge when it's widely used in the industry?
You might have heard that React allows you to build custom components that can be reused throughout the project. In fact, after drawing a mockup of the web application you want to build – using boxes – you might notice some patterns or similarities between the components you create.
With that said, how can you write code as efficiently and clean as possible while dealing with some components that might differ only slightly from another?
In this article, you'll be exploring how to use wrappers for custom components in a basic Typescript React project so that you can practice writing clean code and reusing components efficiently.
Tutorial Requirements
- Node version 14.16.0 or above at the time that this article is written.
- npm, yarn, or another package manager.
- Some prior knowledge in JavaScript and Typescript, or a willingness to learn.
Why is it necessary to use wrappers?
The wrapper is an object that is used to maximize code reuse and consistency. They are used to create and support basic UI elements based on the data - or prop values - provided. These wrapper classes essentially contain an instance of another class or component and provide a new way to use an object.
When you think of using a wrapper, you can think of it as having a new version of an existing object or class. It fundamentally has all the same properties, but with a little extra to give more of an appearance. They are also capable of wrapping around a group of components if they are all passed through as a prop. This is also known as having children inside a component.
Alternatively, wrappers do not only have to enclose some data, but they can be used to unwrap an object and return another data type.
Let's practice our basic understanding of wrappers by writing a component and using a wrapper on the custom component.
Start a React app
In React, there are a few different ways to start an application. For the sake of simplicity, use the create-react-app
utility to create a project structure that you can build on.
On your command line, run the following lines to create the project folders and change into the my-first-react-app directory.
npx create-react-app my-first-react-app cd my-first-react-app
Type the following commands in your terminal to install the necessary packages and dependencies:
npm install --save-dev typescript npm install --save-dev @types/react npm install styled-jsx npm install @types/styled-jsx
Notice that there are already some folders and files created in the directory created for your convenience. Open the src folder and navigate to App.js where you will see some boilerplate code for the React webpage. Replace the contents of the file with the following code:
import './App.css'; function App() { return ( <> <h1>Profile Picture Component and Custom Image Component</h1> </> ) } export default App;
Save your file and enter the command npm start
in your terminal to start the server on localhost:3000/
.
Now, load it in your browser and see that the only thing on your localhost:3000
page is the header. Feel free to kill the server so that you can focus on the code, otherwise leave the terminal open and running to see the changes as you go.
Write a component in React
As mentioned above, React uses components and props to make the code cleaner. Remember that the goal is to simplify the components as much as possible so that you can reuse them throughout the project.
To understand the importance of using wrappers and writing custom components, think about a website that allows users to create a profile and share images. There are plenty of sites out there that follow this format - social media, personal blogs, forums, etc.
Let's say that you want to display the user's profile picture above an image they share. At this point, you might have the idea that an image component must be written. Break that idea down further and you might guess that the image component be reused for the profile picture as well. Perhaps, the only difference is that a profile picture is smaller and displayed as a circular icon than a regular image.
Get started by creating a new folder within the src folder named components. Make two new files:
- CustomImageComponent.tsx
- ProfilePictureComponent.tsx
Since all avatars on a page are essentially based off of an image, you will need to write out the code for the CustomImageComponent.tsx file first.
Copy and paste the following code into CustomImageComponent.tsx:
import React from 'react'; interface Props { alt: string; className: string; height: string; src: string; width: string; } const CustomImageComponent: React.FC<Props> = ({ alt, className, height, src, width }) => ( <> <img alt={alt} className={className} height={height} src={src} width={width} /> </> ); export default CustomImageComponent;
Let's break down everything in this CustomImageComponent
component. Before writing out the details of the component, you will need to define the Props
at the top. Keep in mind that props - which stands for properties - are similar to variables because they are used to pass data into a component.
Each image in your React app will consist of the same properties as elaborated below:
alt
: The alternative text that shows up if the image is being read out loud by a screen reader, or if the image does not appear properly. className
: The name of the class that renders the image in case you want to alter the CSS. height
: The custom height of the image file. src
: The source of the image file. width
: The custom width of the image file.
With all of these props defined, the React project can call on the <img />
tag to render the image file according to the src
. The <img />
component will use the props that are passed in to display your optimized image.
The function also uses JSX – known as JavaScript XML – a JavaScript extension created to make React much more bearable to write. Using JSX should look familiar especially if you have some knowledge in HTML and CSS.
Create a wrapper component in React
A website can have many images of different sizes and use cases. Now that you have the basic CustomImageComponent
defined, you can use this component to create more components based on different use cases.
Let's say you want to have some small, round pictures on your site for the purpose of displaying user profile pictures on a page alongside an image. The idea is to build a new component very similar to the one that was just created, however, you don't want to copy and paste the same exact code from CustomImageComponent
and repeat yourself.
Instead, you'll want to import the CustomImageComponent
and add in additional props that you find necessary to build out the component for profile pictures.
Open up your ProfilePictureComponent.tsx file and copy and paste in the following code:
import React from 'react'; import CustomImageComponent from "./CustomImageComponent"; interface Props { alt: string; className: string; imageClassName: string; src: string; } const ProfilePictureStyling: React.FC<{className: string}> = ({className}) => ( <style jsx global>{` .${className} { border-radius: 50%; object-fit: cover; } `}</style> ) const ProfilePictureComponent: React.FC<Props> = ({ alt, className, imageClassName, src }) => ( <div className={className}> <CustomImageComponent alt={alt} className={imageClassName} height="50px" src={src} width="50px" > <ProfilePictureStyling className={imageClassName}/> </CustomImageComponent> </div> ); export default ProfilePictureComponent;
You'll notice a few new things along with code that looks familiar. Not only are alt
, className
, and src
in the list of props, but there's a new prop named imageClassName
. Two classes are required here because in order to alter the size and shape of the profile picture, you will need to override any default CSS styling.
As you can see, this component file defines two React Functions: ProfilePictureStyling
and ProfilePictureComponent
.
In order for the ProfilePictureComponent
to look different from the CustomImageComponent
, the styling function is created to override the other CSS involved. This React function takes in the className
of the <div>
element that will hold the CustomImageComponent
.
Notice how the CustomImageComponent
already has 2 predefined properties - height
and width
. That's because even though you want to use the other common props, you don't want the user's profile picture to show up as large as the other images on the site. Profile pictures are typically small, so set them both to 50px for now. Feel free to play with the numbers to change the size accordingly.
After instantiating a CustomImageComponent
in the ProfilePictureComponent
, you close off the list of properties and call other remaining data such as ProfilePictureStyling
in our case. Once all the defined props are stated, close off the <div>
and export the component to be used in the main JavaScript page.
Wrap the custom components with a wrapper component
It's time to test out your code.
Save two different pictures to your public folder in the project directory or download twiliologo.png and twilioorglogo.jpg to follow along with the tutorial.
Update the App.js file with the following code. If you saved the images above, the alt
text and src
are already defined:
import './App.css'; import ProfilePictureComponent from "./components/ProfilePictureComponent" import CustomImageComponent from "./components/CustomImageComponent"; function App() { return ( <> <h1>ProfilePicture Component and Custom Image Component</h1> <ProfilePictureComponent alt="Small round Twilio logo for profile picture." className="ProfilePictureTwilioClass" imageClassName="CustomImageClassName" src="/twiliologo.png" > <p>This is my ProfilePicture component!</p> </ProfilePictureComponent> <CustomImageComponent alt="Large Twilio.org logo with heart in speech bubble." className="CustomImageComponentClass" height="100px" src="/twilioorglogo.jpg" width="250px" > </CustomImageComponent> </> ) } export default App;
You're ready to see your custom components in action! If you aren't running npm start
from earlier, go ahead and type that into your terminal. Otherwise, refresh the page to see the profile picture and image you added.
As you can see, the twilioorglogo.jpg file at the bottom is significantly bigger. This is because you defined a height of 100px
and width of 250px
inside the CustomImageComponent
. On the other hand, you didn't have to define any height or width for the ProfilePictureComponent
because these props were already defined in the React function in ProfilePictureComponent.tsx.
Right click the screen to access the dropdown menu on the web page and select Inspect. You can now hover over and click on the images to see more information about the custom component and wrapper that you just created.
Here's the wrapper you used for the <div>
that holds the profile picture:
Here's the custom component for the basic image class:
If you plan on developing with React more, another cool extension that you might consider installing is React Developer Tools. This is a chrome extension that conveniently shows you the breakdown of the React components that are rendered on the page.
You'll see the Components tab in the Internet inspection browser after installing the extension:
Click on Components to see the components used in App.js. Notice how ProfilePictureComponent
wraps around the contents of CustomImageComponent
which consists of <img />
tag and ProfilePictureStyling
.
Meanwhile, the generic CustomImageComponent
is a custom component that does not wrap around anything because it only uses the <img />
tag:
Using wrappers in Typescript React projects
Congratulations! You are now one step closer to writing clean, efficient, and beautiful reusable code for your project. React might have a huge learning curve but investing time into learning how to write your own custom components and wrappers can save you so much time in the long run.
By using React's tools – and connecting with its massive open source community – you will be able to scale up the application that shows user entries in no time. Want a quick challenge? Add a Button
component to your app and write a wrapper for that!
Check out these articles to learn how to build more with React and Typescript:
- Build React projects with a background in Python, Flask, HTML, and CSS
- Learn how to move your project to TypeScript at your own pace
- Integrate TypeScript with Twilio Functions and Twilio Programmable SMS
Reach out to me over email to show me how your first Typescript React projects are going!
Diane Phan is a Developer Network editor on the Developer Voices team. She loves to help programmers tackle difficult challenges that might prevent them from bringing their projects to life. She can be reached at dphan [at] twilio.com or LinkedIn.