Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sastan/react-render-callback
render-prop helper to render anything (Functions, Components, Elements, ...)
https://github.com/sastan/react-render-callback
component-injection function-as-child function-as-child-pattern react render-props
Last synced: about 2 months ago
JSON representation
render-prop helper to render anything (Functions, Components, Elements, ...)
- Host: GitHub
- URL: https://github.com/sastan/react-render-callback
- Owner: sastan
- License: mit
- Created: 2018-09-06T10:14:25.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-05-31T00:02:34.000Z (over 4 years ago)
- Last Synced: 2024-05-22T22:22:51.208Z (7 months ago)
- Topics: component-injection, function-as-child, function-as-child-pattern, react, render-props
- Language: JavaScript
- Homepage:
- Size: 243 KB
- Stars: 9
- Watchers: 2
- Forks: 0
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- awesome-react-render-props - react-render-callback
- awesome-react-render-props - react-render-callback
README
# react-render-callback
> render-prop helper to render anything (Functions, Components, Elements, ...)
[![version][version-badge]][package]
[![MIT License][license-badge]][license]
[![module formats: umd, cjs, and es][module-formats-badge]][unpkg-dist]
[![umd size][size-badge]][unpkg-dist]
[![umd gzip size][gzip-badge]][unpkg-dist][![Build Status][build-badge]][build]
[![Code Coverage][coverage-badge]][coverage]
[![Maintainability][maintainability-badge]][maintainability]
[![PRs Welcome][prs-badge]][prs]
[![Code of Conduct][coc-badge]][coc][![Sponsored by Kenoxa][sponsored-by-badge]][sponsored-by]
[![Semver][semver-badge]][semver]
[![semantic-release][semantic-release-badge]][semantic-release]
[![Greenkeeper badge][greenkeeper-badge]][greenkeeper]## The problem
You want your component to support the [`render prop`][render-prop] [pattern][use-a-render-prop]
with different types of values like
[Function as children][function-as-children],
a [React.Component][react-component] (Component Injection)
or just plain react elements.## This solution
`react-render-callback` frees you from detecting what kind fo [`render prop`][render-prop]
your component is dealing with:```js
import React from 'react'
import renderCallback from 'react-render-callback'class Component from React.Component {
state = {}render() {
// can be any prop like render, component, renderHeader, ...
// children may be a function, a component, an element, ...
return renderCallback(this.props.children, this.state)
}
}
```View an example in [codesandbox.io](https://codesandbox.io/s/48k5p1r764?module=%2FApp.js).
## Highlights
- :package: Super tiny (~650 bytes)
- :ok_hand: Dependency free (except for [Object.assign](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) polyfill)
- :electric_plug: Just Works TM
- :crystal_ball: Tree shaking friendly (ESM, no side effects)
- :books: Well documented
- :100: test coverage
- :sunny: supports React v0.14, v15 and v16
- :family: supports rendering of
- [Stateless Function Components (SFC)](https://reactjs.org/docs/components-and-props.html#functional-and-class-components)
with one argument (the common `props` case) aka _Render Props_ aka _Function as Child_
or [optional with several arguments](#use-createrender-to-pass-down-several-arguments)
- [Class Components](https://reactjs.org/docs/react-component.html) aka _Component Injection_
- [Context](https://reactjs.org/docs/context.html) Provider and Consumer
- [Forward Refs](https://reactjs.org/docs/react-api.html#reactforwardref)
- [Factories](https://reactjs.org/docs/react-api.html#createfactory)
- [Elements](https://reactjs.org/docs/glossary.html#elements)
with [optional support](#use-optionscloneelement) for [cloning][clone-element] to merge props
- primitives like strings, numbers, arrays, ...
- `false`, `null`, `undefined` and `true` are returned as `null`
just like in [JSX](https://reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored)## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [Examples](#examples)
- [Other Solutions](#other-solutions)
- [Credits](#credits)
- [Contributors](#contributors)
- [LICENSE](#license)## Installation
This module is distributed via [npm][npm] which is bundled with [node][node] and
should be installed as one of your project's `dependencies`:```sh
npm install --save react-render-callback
```> This package also depends on `react`. Please make sure you
> have it installed as well.The [Universal Module Definition (UMD)](https://github.com/umdjs/umd) is available
via [unpkg.com](https://unpkg.com/) and exposed as `ReactRenderCallback`.```html
```
## Usage
### API
#### `renderCallback([ renderable [, props [, options ] ] ])`
> renders the given `renderable` with `props`
```js
// esm
import renderCallback from 'react-render-callback'
// commonjs
const renderCallback = require('react-render-callback')
```**renderable** (optional): anything that can be rendered like a function, a component, or elements
- uses [`React.createElement`][create-element]
for react types like
[class components](https://reactjs.org/docs/react-component.html),
[context](https://reactjs.org/docs/context.html) provider or consumer,
[forward refs](https://reactjs.org/docs/react-api.html#reactforwardref),
[factories](https://reactjs.org/docs/react-api.html#createfactory), ...
- invokes stateless function components (SFC) respecting their
[`defaultProps`][default-props]
- not using [`React.createElement`][create-element]
for improved performance
- except the SFC has [`propTypes`](typechecking-with-proptypes) and
`process.env.NODE_ENV` is not `production`, in that case `React.createElement` is used to
enable typechecking with [PropTypes][prop-types]
- gracefully handles other types like string, array,
[react elements][create-element], ...**props** (optional): to pass to `renderable`
**options** (optional):
- `cloneElement` (default: `false`, since: v1.1.0): allows to pass `props` to
the element using [`React.cloneElement`][clone-element]```js
renderCallback(bar, {title: 'foo'})
// --> barrenderCallback(bar, {title: 'foo'}, {cloneElement: true})
// --> bar
```**returns**
- the created react element
- `false`, `null`, `undefined` and `true` are returned as `null`
just like in [JSX](https://reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored)
- the value as is for all other values#### `createRender([ renderable [, options ] ])`
since: v1.1.0
> Returns a function (`(...args) => ...`) to render `renderable` with.
```js
// esm
import {createRender} from 'react-render-callback'
// commonjs
const {createRender} = require('react-render-callback')
```Accepts the same arguments (except `props`) as `renderCallback()`. It exists mainly
to pre-determine (read cache) what type `renderable` is, to prevent these
checks on every invocation.Additionally the returned method accepts more than one argument (since: v1.2.0).
This allows to provide several parameters to the `renderable`.```js
const renderCallback = createRender((a, b, c) => ({a, b, c}))
renderCallback(1, 2, 3)
// -> { a: 1, b: 2, c: 3 }
```> If the `renderable` has a `defaultProps` property only the first parameter is used
> and merged with the `defaultProps`.**returns**
a function (`(...args) => ...`) to render the args
### Examples
A basic example showing the most common use cases can be viewed/edited at [codesandbox.io](https://codesandbox.io/s/48k5p1r764?module=%2FApp.js).
#### Use `options.cloneElement`
[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/mj5py581oy)
> This option allows to pass down `props` without to need to create a function
> within render which merges the defined and provided props.```js
class CountSeconds extends React.Component {
state = {
value: 0,
}componentDidMount() {
this.timer = setInterval(() => {
this.setState(({value}) => ({value: value + 1}))
}, 1000)
}componentWillUnmount() {
clearInterval(this.timer)
}render() {
const {children, render = children} = this.props
return renderCallback(render, this.state, {cloneElement: true})
}
}const DisplayValue = ({prefix = '', value}) => `${prefix}${value}`
const App = ({prefix}) => (
)
```#### Use `createRender` to pass down several arguments
[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/x3j0pxl4lw)
```js
class CountSeconds extends React.Component {
state = {
value: 0,
}reset = () => {
this.setState({value: 0})
}componentDidMount() {
this.timer = setInterval(() => {
this.setState(({value}) => ({value: value + 1}))
}, 1000)
}componentWillUnmount() {
clearInterval(this.timer)
}render() {
const {children, render = children} = this.props
return createRender(render)(this.state.value, this.reset)
}
}const DisplayValue = ({prefix = '', value}) => `${prefix}${value}`
const App = () => (
{(value, reset) => (
reset
)}
)
```#### Use `createRender` to interop with a library which only supports functions as render-prop
[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/1qyqwq14jq)
```js
import Toggle from 'react-toggled'class Toggler extends React.Component {
static defaultProps = {
onLabel: 'Toggled On',
offLabel: 'Toggled Off',
}render() {
const {on, getTogglerProps, onLabel, offLabel} = this.propsreturn (
Toggle me
{on ? onLabel : offLabel}
)
}
}const ToggleView = createRender(Toggler)
const App = () => {ToggleView}
```## Other Solutions
- [`render-props`](https://www.npmjs.com/package/render-props)
- [`react-render-function`](https://www.npmjs.com/package/react-render-function)
- [`@macklinu/render-props`](https://www.npmjs.com/package/@macklinu/render-props)## Credits
A special thanks needs to go to [Kent C. Dodds](https://github.com/kentcdodds) for his great
video series (
[egghead.io](https://egghead.io/instructors/kentcdodds),
[frontendmasters.com](https://frontendmasters.com/teachers/kentcdodds/) and
[youtube.com](https://www.youtube.com/c/kentcdodds-vids)).
His projects are either used in this project ([kcd-scripts](https://github.com/kentcdodds/kcd-scripts))
or are a template for the structure of this project ([downshift](https://github.com/paypal/downshift)).
Make sure to [subscribe](https://buttondown.email/kentcdodds) to his newsletter.## Contributors
Thanks goes to these people ([emoji key][emojis]):
|
Sascha Tandel
[💻](https://github.com/sastan/react-render-callback/commits?author=sastan "Code") [📖](https://github.com/sastan/react-render-callback/commits?author=sastan "Documentation") [🚇](#infra-sastan "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/sastan/react-render-callback/commits?author=sastan "Tests") [👀](#review-sastan "Reviewed Pull Requests") [📝](#blog-sastan "Blogposts") [🐛](https://github.com/sastan/react-render-callback/issues?q=author%3Asastan "Bug reports") [💡](#example-sastan "Examples") [🤔](#ideas-sastan "Ideas, Planning, & Feedback") [📢](#talk-sastan "Talks") |
| :---: |This project follows the [all-contributors][all-contributors] specification.
Contributions of any kind welcome!## LICENSE
MIT
[npm]: https://www.npmjs.com/
[node]: https://nodejs.org
[build-badge]: https://img.shields.io/travis/sastan/react-render-callback.svg?style=flat-square
[build]: https://travis-ci.org/sastan/react-render-callback
[coverage-badge]: https://img.shields.io/codecov/c/github/sastan/react-render-callback.svg?style=flat-square
[coverage]: https://codecov.io/github/sastan/react-render-callback
[version-badge]: https://img.shields.io/npm/v/react-render-callback.svg?style=flat-square
[package]: https://www.npmjs.com/package/react-render-callback
[npmcharts]: http://npmcharts.com/compare/react-render-callback
[license-badge]: https://img.shields.io/npm/l/react-render-callback.svg?style=flat-square
[license]: https://github.com/sastan/react-render-callback/blob/master/LICENSE
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs]: http://makeapullrequest.com
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]: https://github.com/sastan/react-render-callback/blob/master/CODE_OF_CONDUCT.md
[gzip-badge]: http://img.badgesize.io/https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js?compression=gzip&label=umd%20gzip%20size&style=flat-square
[size-badge]: http://img.badgesize.io/https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js?label=umd%20size&style=flat-square
[unpkg-dist]: https://unpkg.com/react-render-callback/dist/
[module-formats-badge]: https://img.shields.io/badge/module%20formats-umd%2C%20cjs%2C%20es-green.svg?style=flat-square
[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key
[maintainability]: https://codeclimate.com/github/sastan/react-render-callback/maintainability
[maintainability-badge]: https://api.codeclimate.com/v1/badges/bdb9f3ea6d70b6181b33/maintainability
[sponsored-by]: https://www.kenoxa.com
[sponsored-by-badge]: https://img.shields.io/badge/Sponsored%20by-Kenoxa-blue.svg
[all-contributors]: https://github.com/kentcdodds/all-contributors
[semantic-release]: https://github.com/semantic-release/semantic-release
[semantic-release-badge]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
[greenkeeper]: https://greenkeeper.io/
[greenkeeper-badge]: https://badges.greenkeeper.io/sastan/react-render-callback.svg
[semver]: http://semver.org/spec/v2.0.0.html
[semver-badge]: https://img.shields.io/badge/SemVer-2.0.0-green.svg
[use-a-render-prop]: https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce
[default-props]: https://reactjs.org/docs/react-component.html#defaultprops
[render-prop]: https://reactjs.org/docs/render-props.html
[function-as-children]: https://reactpatterns.com/#function-as-children
[react-component]: https://reactjs.org/docs/react-component.html
[create-element]: https://reactjs.org/docs/react-api.html#createelement
[clone-element]: https://reactjs.org/docs/react-api.html#cloneelement
[typechecking-with-proptypes]: https://reactjs.org/docs/typechecking-with-proptypes.html
[prop-types]: https://www.npmjs.com/package/prop-types