I. Overview
React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components.
1.1. Containment
Some components don't know their subcomponents ahead of time. This is especially common for components that represent likeSidebar
or Dialog
generic "boxes" .
It is recommended that these components use a special to children prop
pass child elements directly into their output:
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); }
This allows other components to pass arbitrary child objects to them via nested JSX:
function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
Anything inside the <FancyBorder> JSX tag will be passed to the FancyBorder component as the children prop. Due toFancyBorder
rendering {props.children}
internals <div>
, the passed element appears in the final output.
While this is less common, sometimes you may need multiple "holes" in a component. In this case, you can come up with your own convention instead of usingchildren
:
function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); }
React elements like <Contacts /> and <Chat /> are just objects, so you can pass them as props like any other data. This approach may remind you of "slots" in other libraries, but there are no restrictions on the props you can pass in React.
1.2/Specialization
Sometimes we think of components as "special cases" of other components. For example, we can say that a WelcomeDialog is a special case of Dialog.
In React, this can also be achieved through composition, where a more "specific" component renders a more "generic" component, configured with props:
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ); } function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }
Composition works equally well for components defined as classes:
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> {props.children} </FancyBorder> ); } class SignUpDialog extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.handleSignUp = this.handleSignUp.bind(this); this.state = {login: ''}; } render() { return ( <Dialog title="Mars Exploration Program" message="How should we refer to you?"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog> ); } handleChange(e) { this.setState({login: e.target.value}); } handleSignUp() { alert(`Welcome aboard, ${this.state.login}!`); } }
What about inheritance?
At Facebook, we use React in thousands of components, and we haven't found any use cases that suggest creating a component inheritance hierarchy.
Props and composition give you all the flexibility you need to customize the appearance and behavior of your components in an unambiguous and safe way. Remember that components can accept arbitrary props, including primitive values, React elements or functions.
If you want to reuse non-UI functionality between components, we recommend unpacking it into a separate JavaScript module. Components can import it and use the function, object or class without extending it.