You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
8.0 KiB
267 lines
8.0 KiB
8 years ago
|
---
|
||
|
id: components-and-props
|
||
|
title: Components and Props
|
||
|
permalink: docs/components-and-props.html
|
||
8 years ago
|
redirect_from:
|
||
|
- "docs/reusable-components.html"
|
||
8 years ago
|
- "docs/reusable-components-zh-CN.html"
|
||
8 years ago
|
- "docs/transferring-props.html"
|
||
8 years ago
|
- "docs/transferring-props-it-IT.html"
|
||
|
- "docs/transferring-props-ja-JP.html"
|
||
|
- "docs/transferring-props-ko-KR.html"
|
||
|
- "docs/transferring-props-zh-CN.html"
|
||
8 years ago
|
- "tips/props-in-getInitialState-as-anti-pattern.html"
|
||
|
- "tips/communicate-between-components.html"
|
||
8 years ago
|
prev: rendering-elements.html
|
||
|
next: state-and-lifecycle.html
|
||
8 years ago
|
---
|
||
|
|
||
|
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
|
||
|
|
||
|
Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.
|
||
|
|
||
|
## Functional and Class Components
|
||
|
|
||
|
The simplest way to define a component is to write a JavaScript function:
|
||
|
|
||
|
```js
|
||
|
function Welcome(props) {
|
||
|
return <h1>Hello, {props.name}</h1>;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
This function is a valid React component because it accepts a single "props" object argument with data and returns a React element. We call such components "functional" because they are literally JavaScript functions.
|
||
|
|
||
|
You can also use an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) to define a component:
|
||
|
|
||
|
```js
|
||
|
class Welcome extends React.Component {
|
||
|
render() {
|
||
|
return <h1>Hello, {this.props.name}</h1>;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The above two components are equivalent from React's point of view.
|
||
|
|
||
7 years ago
|
Classes have some additional features that we will discuss in the [next sections](/docs/state-and-lifecycle.html). Until then, we will use functional components for their conciseness.
|
||
8 years ago
|
|
||
|
## Rendering a Component
|
||
|
|
||
|
Previously, we only encountered React elements that represent DOM tags:
|
||
|
|
||
|
```js
|
||
|
const element = <div />;
|
||
|
```
|
||
|
|
||
|
However, elements can also represent user-defined components:
|
||
|
|
||
|
```js
|
||
|
const element = <Welcome name="Sara" />;
|
||
|
```
|
||
|
|
||
|
When React sees an element representing a user-defined component, it passes JSX attributes to this component as a single object. We call this object "props".
|
||
|
|
||
|
For example, this code renders "Hello, Sara" on the page:
|
||
|
|
||
|
```js{1,5}
|
||
|
function Welcome(props) {
|
||
|
return <h1>Hello, {props.name}</h1>;
|
||
|
}
|
||
|
|
||
|
const element = <Welcome name="Sara" />;
|
||
|
ReactDOM.render(
|
||
|
element,
|
||
|
document.getElementById('root')
|
||
|
);
|
||
|
```
|
||
|
|
||
|
[Try it on CodePen.](http://codepen.io/gaearon/pen/YGYmEG?editors=0010)
|
||
|
|
||
|
Let's recap what happens in this example:
|
||
|
|
||
|
1. We call `ReactDOM.render()` with the `<Welcome name="Sara" />` element.
|
||
|
2. React calls the `Welcome` component with `{name: 'Sara'}` as the props.
|
||
|
3. Our `Welcome` component returns a `<h1>Hello, Sara</h1>` element as the result.
|
||
|
4. React DOM efficiently updates the DOM to match `<h1>Hello, Sara</h1>`.
|
||
|
|
||
|
>**Caveat:**
|
||
|
>
|
||
|
>Always start component names with a capital letter.
|
||
|
>
|
||
|
>For example, `<div />` represents a DOM tag, but `<Welcome />` represents a component and requires `Welcome` to be in scope.
|
||
|
|
||
|
## Composing Components
|
||
|
|
||
|
Components can refer to other components in their output. This lets us use the same component abstraction for any level of detail. A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components.
|
||
|
|
||
|
For example, we can create an `App` component that renders `Welcome` many times:
|
||
|
|
||
|
```js{8-10}
|
||
|
function Welcome(props) {
|
||
|
return <h1>Hello, {props.name}</h1>;
|
||
|
}
|
||
|
|
||
|
function App() {
|
||
|
return (
|
||
|
<div>
|
||
|
<Welcome name="Sara" />
|
||
|
<Welcome name="Cahal" />
|
||
|
<Welcome name="Edite" />
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
ReactDOM.render(
|
||
|
<App />,
|
||
|
document.getElementById('root')
|
||
|
);
|
||
|
```
|
||
|
|
||
|
[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQKPr?editors=0010)
|
||
|
|
||
|
Typically, new React apps have a single `App` component at the very top. However, if you integrate React into an existing app, you might start bottom-up with a small component like `Button` and gradually work your way to the top of the view hierarchy.
|
||
|
|
||
|
>**Caveat:**
|
||
|
>
|
||
|
>Components must return a single root element. This is why we added a `<div>` to contain all the `<Welcome />` elements.
|
||
|
|
||
|
## Extracting Components
|
||
|
|
||
|
Don't be afraid to split components into smaller components.
|
||
|
|
||
|
For example, consider this `Comment` component:
|
||
|
|
||
|
```js
|
||
|
function Comment(props) {
|
||
|
return (
|
||
|
<div className="Comment">
|
||
|
<div className="UserInfo">
|
||
|
<img className="Avatar"
|
||
8 years ago
|
src={props.author.avatarUrl}
|
||
|
alt={props.author.name}
|
||
|
/>
|
||
8 years ago
|
<div className="UserInfo-name">
|
||
|
{props.author.name}
|
||
|
</div>
|
||
|
</div>
|
||
|
<div className="Comment-text">
|
||
|
{props.text}
|
||
|
</div>
|
||
|
<div className="Comment-date">
|
||
|
{formatDate(props.date)}
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
[Try it on CodePen.](http://codepen.io/gaearon/pen/VKQwEo?editors=0010)
|
||
|
|
||
|
It accepts `author` (an object), `text` (a string), and `date` (a date) as props, and describes a comment on a social media website.
|
||
|
|
||
|
This component can be tricky to change because of all the nesting, and it is also hard to reuse individual parts of it. Let's extract a few components from it.
|
||
|
|
||
|
First, we will extract `Avatar`:
|
||
|
|
||
8 years ago
|
```js{3-6}
|
||
8 years ago
|
function Avatar(props) {
|
||
|
return (
|
||
|
<img className="Avatar"
|
||
8 years ago
|
src={props.user.avatarUrl}
|
||
|
alt={props.user.name}
|
||
|
/>
|
||
8 years ago
|
);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The `Avatar` doesn't need to know that it is being rendered inside a `Comment`. This is why we have given its prop a more generic name: `user` rather than `author`.
|
||
|
|
||
|
We recommend naming props from the component's own point of view rather than the context in which it is being used.
|
||
|
|
||
|
We can now simplify `Comment` a tiny bit:
|
||
|
|
||
|
```js{5}
|
||
|
function Comment(props) {
|
||
|
return (
|
||
|
<div className="Comment">
|
||
|
<div className="UserInfo">
|
||
|
<Avatar user={props.author} />
|
||
|
<div className="UserInfo-name">
|
||
|
{props.author.name}
|
||
|
</div>
|
||
|
</div>
|
||
|
<div className="Comment-text">
|
||
|
{props.text}
|
||
|
</div>
|
||
|
<div className="Comment-date">
|
||
|
{formatDate(props.date)}
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Next, we will extract a `UserInfo` component that renders an `Avatar` next to user's name:
|
||
|
|
||
|
```js{3-8}
|
||
|
function UserInfo(props) {
|
||
|
return (
|
||
|
<div className="UserInfo">
|
||
|
<Avatar user={props.user} />
|
||
|
<div className="UserInfo-name">
|
||
|
{props.user.name}
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
This lets us simplify `Comment` even further:
|
||
|
|
||
|
```js{4}
|
||
|
function Comment(props) {
|
||
|
return (
|
||
|
<div className="Comment">
|
||
|
<UserInfo user={props.author} />
|
||
|
<div className="Comment-text">
|
||
|
{props.text}
|
||
|
</div>
|
||
|
<div className="Comment-date">
|
||
|
{formatDate(props.date)}
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
[Try it on CodePen.](http://codepen.io/gaearon/pen/rrJNJY?editors=0010)
|
||
|
|
||
|
Extracting components might seem like grunt work at first, but having a palette of reusable components pays off in larger apps. A good rule of thumb is that if a part of your UI is used several times (`Button`, `Panel`, `Avatar`), or is complex enough on its own (`App`, `FeedStory`, `Comment`), it is a good candidate to be a reusable component.
|
||
|
|
||
|
## Props are Read-Only
|
||
|
|
||
|
Whether you declare a component [as a function or a class](#functional-and-class-components), it must never modify its own props. Consider this `sum` function:
|
||
|
|
||
|
```js
|
||
|
function sum(a, b) {
|
||
|
return a + b;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Such functions are called ["pure"](https://en.wikipedia.org/wiki/Pure_function) because they do not attempt to change their inputs, and always return the same result for the same inputs.
|
||
|
|
||
|
In contrast, this function is impure because it changes its own input:
|
||
|
|
||
|
```js
|
||
|
function withdraw(account, amount) {
|
||
|
account.total -= amount;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
React is pretty flexible but it has a single strict rule:
|
||
|
|
||
|
**All React components must act like pure functions with respect to their props.**
|
||
|
|
||
7 years ago
|
Of course, application UIs are dynamic and change over time. In the [next section](/docs/state-and-lifecycle.html), we will introduce a new concept of "state". State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule.
|