Leveraging render props

Imagine implementing a feature that is composed of several smaller components – like what you've been working on in this chapter. The MyFeature component depends on ArticleList and AddArticle. Now imagine using MyFeature in different parts of your application where it makes sense to use a different implementation of ArticleList or AddArticle. The fundamental challenge is substituting one component for another.

Render props are a nice way to address this challenge. The idea is that you pass a property to your component whose value is a function that returns a component to render. This way, instead of having the feature component directly depend on its child components, you can configure them as you like; they pass them in as render prop values.

Render props aren't a React 16 feature. They're a technique whose popularity increase coincided with the release of React 16. It's an officially recognized way to deal with dependency and substitution problems. You can read more about render props here: https://reactjs.org/docs/render-props.html
Let's look at an example. Instead of having MyFeature directly depend on AddArticle and ArticleList, you can pass them as render props. Here's what the render() method of MyFeature looks like when it's using render props to fill in the holes where <AddArticle> and <ArticleList> used to be:
// Now when <MyFeature> is rendered, it uses render props to
// render <ArticleList> and <AddArticle>. It no longer has
// a direct dependency to these components.
render() {
const { articles, title, summary } = this.data.toJS();
const {
props: { addArticle, articleList },
onClickAdd,
onClickToggle,
onClickRemove,
onChangeTitle,
onChangeSummary
} = this;

return (
<section>
{addArticle({
title,
summary,
onChangeTitle,
onChangeSummary,
onClickAdd
})}
{articleList({ articles, onClickToggle, onClickRemove })}
</section>
);
}

The addArticle() and articleList() functions are called with the same property values that would have been passed to <AddArticle> and <ArticleList>, respectively. The difference now is that this module no longer imports AddArticle or ArticleList as dependencies.

Now let's take a look at the index.js where <MyFeature> is rendered:

// <MyFeature> is now passed a "addArticle" and a "articleList"
// property. These are functions that return components to render.
render(
<MyFeature
addArticle={({
title,
summary,
onChangeTitle,
onChangeSummary,
onClickAdd
}) => (
<AddArticle
name="Articles"
title={title}
summary={summary}
onChangeTitle={onChangeTitle}
onChangeSummary={onChangeSummary}
onClickAdd={onClickAdd}
/>
)}
articleList={({ articles, onClickToggle, onClickRemove }) => (
<ArticleList
articles={articles}
onClickToggle={onClickToggle}
onClickRemove={onClickRemove}
/>
)}
/>,
document.getElementById('root')
);

There's a lot more going on here now than there was when it was just <MyFeature> being rendered. Let's break down why that is. Here is where you pass the addArticle and articleList render props. These prop values are functions that accept argument values from MyComponent. For example, the onClickToggle() function comes from MyFeature and is used to change the state of that component. You can use the render prop function to pass this to the component that will be rendered, along with any other values. The return value of these functions are what is ultimately rendered.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.2.122