Create a Simple Reusable React Component

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 5 years ago
Updated 2 years ago

Just like in regular JavaScript, when you want to reuse code, you create a function. With React, you create components. In this lesson, we'll walk through the process of creating custom React components and you'll walk away with a deep understanding of how to create and use basic components to compose a larger component you render. We will look at how JSX works by calling React.creatElement under the hood.

[00:00] Here, I have a div with a child that has hello world in it. We're going to go ahead and duplicate these, and we'll see we have two. I don't want to repeat myself, so I'm going to actually extract this to a variable called hello world. Then I can just interpolate that directly in my JSX. I refresh. I see exactly the same thing.

[00:22] Now, let's say that I wanted one of them to say hello world and the other to say goodbye world. In JavaScript, when we want to reuse code and parameterize that code, we use a function. I'm going to use an arrow function here. This arrow function is going to take an argument. I'm going to call that props.

[00:39] Props is going to be an object that is going to have a message property on it, so I'll say props.msg, message. I'll go ahead and change this function to message. Then in the place of hello world here, I'm going to say message with an object with an msg prop. That's going to be hello world.

[00:59] We'll do the same here, message with msg, goodbye world. We'll do that. Refresh here. We'll have hello world and goodbye world. Sweet. We've been able to take some JSX, wrap it in a function, and make a function call to message there.

[01:17] Unfortunately, function calls don't really compose quite as well as JSX does, so let's see how we can turn this into JSX to make it compose a little bit better. JSX compiles down to React.create element call. Let's start out with React.create element and see how we can convert that to JSX.

[01:33] One neat thing about the React create element API is that it cannot only take a string indicating what element we want to have rendered, like div or span, but it can also take a function. It will pass the props to the function, and that function presumably will render some more elements. In our case, the message function is rendering a div.

[01:52] With that in mind, the function that we want to create an element out of is this message function. The props we're going to pass is this object that has the message property for hello world. If I save that and refresh, we see that everything is working just fine. Let's go ahead and update the goodbye world as well. Everything's working great with that too.

[02:11] When we wanted to switch from React create element with a quotes div to JSX div, we simply wrote open caret div. Let's go ahead and do open caret message here and see what happens with that. We're going to see a warning that says that the tag message is unrecognized in the browser. If I go here, I'm going to see that message is actually being rendered.

[02:33] That's not exactly what I'm really going for here. I want to render my component. I want to have this function called using React create element. Let's go ahead and take a look at what's happening here. We're going to go to the Babel REPL because, remember, it's Babel that's transpiling this JSX statement into a React create element.

[02:51] If I copy this over, then we're going to see it's React create element with quotes message. That's why this message isn't being referenced if I put this up here. The reason is that we have this variable message, but it's using the string message.

[03:07] For JSX to differentiate whether you're talking about a variable that's in scope or a raw DOM element, you need to capitalize your component. Now it's going to be referencing some variable name that I have available to me. In this case, I'll capitalize the M. Now, this message is being referenced in this create element call.

[03:27] If we apply that to our scenario, we're going to just remove this here. I'm going to take both of these, do a capital M. We'll open a caret there. Then we'll do a self-closing element here. Then let's go back. We'll remove some of this JavaScript syntax in favor of JSX. If we save that, we'll refresh.

[03:48] Of course, we do need to capitalize our component here. Then we have exactly what we're looking for. We have this hello world and goodbye world referencing the message component that we created. Now, we can reuse this all over the place. We can compose these things together.

[04:06] Particularly, if we were to change the msg prop to the children prop, we'd say children, then we can change msg to children here. We refresh and we get the exact same thing. The nice thing about the children prop is we can use it just like we would regular HTML as part of the child of this message component.

[04:30] Now we can compose these things together quite nicely. I could even put message within a message. If we look at the resulting HTML, we're going to see that we have our container, then we have our first message component, we have that string message, hello world, and then we have another message component with the string goodbye world.

[04:49] To review, to create a component that is reusable throughout your application and as composable as any other of the JSX that you have available to you is you create a function that has a capital letter as the first character.

[05:02] Then that will receive props. You can use those props in whatever it is that you return. Then you're going to return some React elements. Then you can use those just like you do with the div or span or anything that you do with JSX.

ahairshi
ahairshi
~ 5 years ago

Hi,

I see an arrow function with no arguments for props in the transcript. Please change it

from

const message = () => <div>{props.msg}</div>

to

const message = props => <div>{props.msg}</div>
Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Thanks ahairshi!

RentPath User 5
RentPath User 5
~ 5 years ago

@Kent; how do you move/get/run the babel compiler to compile/display the message at the 3.0 marker in your video?

Thank you and happy holidays...

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

See: https://babeljs.io/repl/

:)

RentPath User 5
RentPath User 5
~ 5 years ago

Thanks for your quick response; I did just that and came back to see ur answer.... my bad... thanks again,, enjoying the course a great deal, second time around...

:)

Kingsley Silas Chijioke
Kingsley Silas Chijioke
~ 4 years ago

@Kent, I am trying to play with the code further - trying to pass a prop as className. Any reason why the code below doesn't work?

  const Message = props => <div {props.className}>{props.children}</div>
  const element = (
    <div className="container">
      <Message>Hello World
        <Message>Next!</Message>
      </Message>
    </div>
  )
Kent C. Dodds
Kent C. Doddsinstructor
~ 4 years ago

Hey Kingsley,

Your syntax is incorrect. Also, you need to pass the prop to the Message component. Try this:

  const Message = props => <div className={props.className}>{props.children}</div>
  const element = (
    <div className="container">
      <Message className="first-message">Hello World
        <Message className="second-message">Next!</Message>
      </Message>
    </div>
  )

I hope that helps. Good luck!

Kingsley Silas Chijioke
Kingsley Silas Chijioke
~ 4 years ago

I tried this

var Message = function Message(props) {
  return React.createElement(
    "div",
    null,
    props.children,
    props.className
  );
};
var element = React.createElement(
  "div",
  { className: "container" },
  React.createElement(
    Message,
    null,
    "Hello World",
    { className: "test" },
    React.createElement(
      Message,
      null,
      "Next!"
    )
  )
);

That gave this error;

Uncaught Error: Objects are not valid as a React child (found: object with keys {className}). If you meant to render a collection of children, use an array instead.
Kingsley Silas Chijioke
Kingsley Silas Chijioke
~ 4 years ago

I am trying to see if it's possible to pass a className to either of the divs via props.

Kingsley Silas Chijioke
Kingsley Silas Chijioke
~ 4 years ago

Okay, I get it now. They are components, thus it is impossible to give them a className. Right?

Kent C. Dodds
Kent C. Doddsinstructor
~ 4 years ago

Well, as you can see in my example, I'm passing the prop called className to the component, and it uses that prop to forward it into the underlying div.

Fortech, RO 16013724
Fortech, RO 16013724
~ 4 years ago

Hey Kent,

I have identified two issues in the transcript:

    1. <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script> (src instead of type)
    1. the rootElement is not defined

Thanks for the course!

Kent C. Dodds
Kent C. Doddsinstructor
~ 4 years ago

Thanks Fortech! I'll let the egghead folks know.

Ifeoluwa Sobogun
Ifeoluwa Sobogun
~ 3 years ago

Maybe it's just me, but I've tried using these tutorials three times and it seems too fast-paced.

Rian Sanjaya Ng
Rian Sanjaya Ng
~ 3 years ago

Hi Kent greate course. I notice the code is sandbox there is a folder src with index.js inside, and in the index.js it somehow use parcel.js I wonder when this index.js is called and what it does ?

Keith Price
Keith Price
~ 3 years ago

Coming from VB programming, I find myself struggling with the idea that props don't have to be defined in the receiving component. Anything we pass to it just becomes a prop. I kinda get it but it still keeps tripping me up when trying to understand existing code.

Keith Price
Keith Price
~ 3 years ago

I was surprised that we can assign html to a variable with no enclosures, such as quotes.

const greeting = (props) => <div> { props.msg } </div>
Keith Price
Keith Price
~ 3 years ago

Can you help us understand all the different syntax supported by arrow functions? I keep getting lost when I see some with parenths, some without, some with empty parenths. Some with curly braces, some without, etc. I can look up the supported syntax, but I can't figure out when I should (or must) use one over another?

Keith Price
Keith Price
~ 3 years ago

So, does capitalizing a function like that (Message) essentially make it a component variable (that is, a variable that holds a component)?

Keith Price
Keith Price
~ 3 years ago

Is there a guideline or rule to help us know when to use name=value vs name: value? I find it very confusing.

<Welcome msg= "Welcome to our site" />

And I guess, the reason the above didn't require {} is because Welcome is defined as a component variable?