Props! — and how to pass props to components in React . (part_2)

Sanje Qi
3 min readAug 25, 2019

--

part 1

HOW TO PASS COMPONENTS AS PROPS?

Before you have learned about React’s children prop to pass a component as prop to another component.

const User = ({ user }) => (<Profile user={user}><AvatarRound user={user} /></Profile>);const Profile = ({ user, children }) => (<div className="profile"><div>{children}</div><div><p>{user.name}</p></div></div>);const AvatarRound = ({ user }) => (<img className="round" alt="avatar" src={user.avatarUrl} />);

However, what if you want to pass more than one component and place them at different positions? Then again you don’t need to use the children prop and instead you just use regular props:

const User = ({ user }) => (<Profileuser={user}avatar={<AvatarRound user={user} />}biography={<BiographyFat user={user} />}/>);const Profile = ({ user, avatar, biography }) => (<div className="profile"><div>{avatar}</div><div><p>{user.name}</p>{biography}</div></div>);const AvatarRound = ({ user }) => (<img className="round" alt="avatar" src={user.avatarUrl} />);const BiographyFat = ({ user }) => (<p className="fat">{user.biography}</p>);

Often this approach is used when having a surrounding layout component which takes multiple components as content with props. Now you can exchange the Avatar or Biography components dynamically with other components such as:

const AvatarSquare = ({ user }) => (<img className="square" alt="avatar" src={user.avatarUrl} />);const BiographyItalic = ({ user }) => (<p className="italic">{user.biography}</p>);

Many people refer to this as slot pattern in React. You can find a working minimal project on GitHub. And again, that’s how composition in React shines. You don’t need to touch the Profile component. Moreover, you don’t need to pass props, in this case the user, multiple levels down the component tree, but rather pass it to the slotted components.

CHILDREN AS A FUNCTION

The concept of children as a function or child as a function, also called render prop, is one of the advanced patterns in React (next to higher-order components). The components which implement this pattern can be called render prop components.

The following implementations can be difficult to follow when not having used render props in React before. Please read up this article as introduction to render props in React first.

First, let’s start with the render prop. Basically it is a function passed as prop (usually called render, but the name can be anything). The function receives arguments (in this case the amount), but also renders JSX (in this case the components for the currency conversion).

const App = () => (<div><h1>US Dollar to Euro:</h1><Amount render={amount => <Euro amount={amount} />} /><h1>US Dollar to Pound:</h1><Amount render={amount => <Pound amount={amount} />} /></div>);class Amount extends Component {constructor(props) {super(props);this.state = {amount: 0,};}onIncrement = () => {this.setState(state => ({ amount: state.amount + 1 }));};onDecrement = () => {this.setState(state => ({ amount: state.amount - 1 }));};render() {return (<div><button type="button" onClick={this.onIncrement}>+</button><button type="button" onClick={this.onDecrement}>-</button><p>US Dollar: {this.state.amount}</p>{this.props.render(this.state.amount)}</div>);}}const Euro = ({ amount }) => <p>Euro: {amount * 0.86}</p>;const Pound = ({ amount }) => <p>Pound: {amount * 0.76}</p>;

Second, refactor the whole thing from having a render prop to having the children as a function:

const App = () => (<div><h1>US Dollar to Euro:</h1><Amount>{amount => <Euro amount={amount} />}</Amount><h1>US Dollar to Pound:</h1><Amount>{amount => <Pound amount={amount} />}</Amount></div>);class Amount extends Component {constructor(props) {super(props);this.state = {amount: 0,};}onIncrement = () => {this.setState(state => ({ amount: state.amount + 1 }));};onDecrement = () => {this.setState(state => ({ amount: state.amount - 1 }));};render() {return (<div><button type="button" onClick={this.onIncrement}>+</button><button type="button" onClick={this.onDecrement}>-</button><p>US Dollar: {this.state.amount}</p>{this.props.children(this.state.amount)}</div>);}}const Euro = ({ amount }) => <p>Euro: {amount * 0.86}</p>;const Pound = ({ amount }) => <p>Pound: {amount * 0.76}</p>;

That’s essentially everything to distinguish between a render prop or a children as a function in a render prop component. The former is passed as a normal prop and the latter is passed as a children prop. You have seen before that functions can be passed as callback handlers (e.g. button click) to React components, but this time the function is passed to actually render something whereas the responsibility for what to render was partially moved outside of the render prop component but the props are provided by the render prop component itself. More to follow on this topic.

Source: StackOverflow, Robin Wieruch, Medium, ReactJs, MDN

--

--