• No results found

Communication between components

Reusing functions is one of our goals as developers, and we have seen how React makes it easy to create reusable components.

Reusable components can be shared across multiple domains of your application to avoid duplication.

Small components with a clean interface can be composed together to create complex applications that are powerful and maintainable at the same time.

Composing React components is pretty straightforward; you just have to include them in the render method:

const Profile = ({ user }) => ( <div>

<Picture profileImageUrl={user.profileImageUrl} />

<UserName name={user.name} screenName={user.screenName} /> </div>

)

Profile.propTypes = {

user: React.PropTypes.object, }

For example, you can create a Profile component by simply composing a

Picture component to display the profile image and a UserName component to display the name and the screen name of the user.

In this way, you can produce new parts of the user interface very quickly, writing only a few lines of code.

Whenever you compose components, as in the preceding example, you share data between them using props.

Props are the way a parent component can pass its data down the tree to every component that needs it (or part of it).

When a component passes some props to another component, it is called the Owner, irrespective of the parent-child relation between them.

For example, in the preceding snippet, Profile is not the direct parent of Picture (the div tag is) but Profile owns Picture because it passes down the props to it.

Children

There is a special prop that can be passed from the owners to the components defined inside their render method; it is called children.

In the React documentation, it is described as opaque because it is a property that does not tell anything about the value it contains.

Subcomponents defined inside the render method of a parent component usually receive props passed as attributes of the component itself in JSX, or as a second parameter of the createElement function.

Components can also be defined with nested components inside them, and they can access those children using the children prop.

Consider that we have a Button component that has a text property representing the text of the button:

const Button = ({ text }) => (

<button className="btn">{text}</button> )

Button.propTypes = {

text: React.PropTypes.string, }

It can be used in the following way:

<Button text="Click me!" />

And it renders the following code:

<button class="btn">Click me!</button>

Now, suppose we want to use the same button with the same class name in multiple parts of our application, and we also want to be able to display more than a simple string. In fact, our UI consists of buttons with text, buttons with text and icons, and buttons with text and labels.

In most cases, a good solution would be to add multiple parameters to the Button or to create different versions of the Button, each one with its single specialization, for example, IconButton.

However, if we realize that our Button could be just a wrapper, and we want to be able to render any element inside it, we can use the children property.

We can easily do that by changing the Button component from the preceding example to be similar to the following snippet:

const Button = ({ children }) => (

<button className="btn">{children}</button> )

Button.propTypes = {

children: React.PropTypes.array, }

Applying this change, we are not limited to a simple single text property but we can pass any element to Button, and it is rendered in place of the children property.

In this case, any element that we wrap inside the Button component will be rendered as a child of the button element with the btn class name.

For example, if we want to render an image inside the button and a text wrapped into a span, we can do this:

<Button>

<img src="..." alt="..." /> <span>Click me!</span> </Button>

The preceding snippet gets rendered in the browser as follows:

<button className="btn"> <img src="..." alt="..." /> <span>Click me!</span> </button>

This is a pretty convenient way to allow components to accept any children elements and wrap those elements inside a predefined parent.

Now we can pass images, labels, and even other React components inside the Button and they will be rendered as its children.

As you can see in the preceding example, we defined the children property as an array, which means that we can pass any number or elements as the component's children.

We can pass a single child, as shown in the following code:

<Button>

<span>Click me!</span> </Button>

If we pass a single child, we get this:

Failed prop type: Invalid prop `children` of type `object` supplied to `Button`, expected `array`.

This is because, when a component has a single child, React optimizes the creation of the elements and avoids allocating an array for performance reasons.

We can easily fix this warning by setting the children prop to accept the following prop types: Button.propTypes = { children: React.PropTypes.oneOfType([ React.PropTypes.array, React.PropTypes.element, ]), }