Skip to content
This repository has been archived by the owner on Sep 10, 2022. It is now read-only.

Commit

Permalink
Merge pull request #26 from acdlite/renderComponent
Browse files Browse the repository at this point in the history
Add renderComponent(), renderNothing(), and update docs
  • Loading branch information
acdlite committed Oct 22, 2015
2 parents 3131543 + ce8e472 commit e84f857
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 53 deletions.
7 changes: 6 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2,

//Temporaerirly disabled due to a possible bug in babel-eslint (todomvc example)
"no-unused-vars": [2, {
"args": "after-used",
"argsIgnorePattern": "^_$"
}],

//Temporarily disabled due to a possible bug in babel-eslint (todomvc example)
"block-scoped-var": 0,
// Temporarily disabled for test/* until babel/babel-eslint#33 is resolved
"padded-blocks": 0
Expand Down
54 changes: 48 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,9 @@ This is a good option for library authors who don't want to bloat their bundle s

Recompose includes some lodash modules, like `curry` and `compose`, as dependencies. If you're already using lodash, then the net bundle increase from using Recompose will be even smaller.

## Background
## What is microcomponentization all about?

### What is microcomponentization all about?

Forget ES6 classes vs. `createClass()`. React 0.14 introduces **[stateless function components](https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components)**, which allow you to express components as pure functions:
Forget ES6 classes vs. `createClass()`. React 0.14 introduces **[stateless function components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions)**, which allow you to express components as pure functions:

```js
const Greeting = props => (
Expand All @@ -97,17 +95,61 @@ We call the practice of writing small, pure, reusable components **microcomponen

Note that although Recompose encourages the use of function components whenever possible, it works with normal React components as well.

### Higher-order components made easy
## Higher-order components made easy

Most of the time when we talk about composition in React, we're talking about composition of components. For example, a `<Blog>` component may be composed of many `<Post>` components, which are composed of many `<Comment>` components.

However, that's only the beginning. Recompose focuses on another unit of composition: **higher-order components** (HoCs). HoCs are functions that accept a base component and return a new component with additional functionality. They can be used to abstract common tasks into reusable pieces.

Recompose provides a toolkit of helper functions for creating higher-order components. Most of these helpers are themselves are higher-order components. You can compose the helpers together to make new HoCs, or apply them to a base component.

## Should I use this? Performance and other concerns

If function composition doesn't scare you, then yes, I think so. I believe using higher-order component helpers leads to smaller, more focused components, and provides a better programming model than using classes for operations -- like `mapProps()` or `shouldUpdate()` -- that aren't inherently class-y.

That being said, any abstraction over an existing API is going to come with trade-offs. There is a performance overhead when introducing a new component to the tree. I suspect this cost is negligible compared to the gains achieved by blocking subtrees from re-rendering using `shouldComponentUpdate()` — which Recompose makes easy with its `shouldUpdate()` and `onlyUpdateForKeys()` helpers. In the future, I'll work on some benchmarks so we know what we're dealing with.

However, many of Recompose's higher-order component helpers are implemented using stateless function components rather than class components. Eventually, React will include optimizations for stateless components. Until then, we can do our own optimizations by taking advantage of referential transparency. In other words, creating an element from a stateless function is effectively* the same as calling the function and returning its output.

* *Stateless function components are not referentially transparent if they access context; we detect that by checking for the existence of `contextTypes`.*

To accomplish this, Recompose uses a special version of `createElement()` that returns the output of stateless functions instead of creating a new element. For class components, it uses the built-in `React.createElement()`.

I wouldn't recommend this approach for most of the stateless function components in your app. First of all, you lose the ability to use JSX, unless you monkey-patch `React.createElement()`, which is a bad idea. Second, you lose lazy evaluation. Consider the difference between these two components, given that `Comments` is a stateless function component:

```js
// With lazy evaluation
const Post = ({ title, content, comments, showComments }) => {
const theComments = <Comments comments={comments} />;
return (
<article>
<h1>title</h1>
<div>{content}</div>
{showComments ? theComments : null}
</article>
);
});

// Without lazy evaluation
const Post = ({ title, content, comments, showComments }) => {
const theComments = Comments({ comments });
return (
<article>
<h1>title</h1>
<div>{content}</div>
{showComments ? theComments : null}
</article>
);
});
```

In the first example, the `Comments` function is used to create a React element, and will only be evaluated *by React* if `showComments` is true. In the second example, the `Comments` function is evaluated on every render of `Post`, regardless of the value of `showComments`. This can be fixed by putting the `Comments` call inside the ternary statement, but it's easy to neglect this distinction and create performance problems. As a general rule, you should always create an element.

So why does Recompose break this rule? Because it's a utility library, not an application. Just as it's okay for lodash to use for-loops as an implementation detail of its helper functions, it should be okay for Recompose to eschew intermediate React elements as a (temporary) performance optimization.

## Features

### Automatic currying
## Automatic currying

Recompose functions are component-last and curried by default. This makes them easy to compose:

Expand Down

0 comments on commit e84f857

Please sign in to comment.