react-render-callback
v1.2.5
Published
render-prop helper to render anything (Functions, Components, Elements, ...)
Downloads
48
Maintainers
Readme
react-render-callback
render-prop helper to render anything (Functions, Components, Elements, ...)
The problem
You want your component to support the render prop
pattern
with different types of values like
Function as children,
a React.Component (Component Injection)
or just plain react elements.
This solution
react-render-callback
frees you from detecting what kind fo render prop
your component is dealing with:
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.
Highlights
- :package: Super tiny (~600 bytes)
- :ok_hand: Dependency free (except for 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)
with one argument (the common
props
case) aka Render Props aka Function as Child or optional with several arguments - Class Components aka Component Injection
- Context Provider and Consumer
- Forward Refs
- Factories
- Elements with optional support for cloning to merge props
- primitives like strings, numbers, arrays, ...
false
,null
,undefined
andtrue
are returned asnull
just like in JSX
- Stateless Function Components (SFC)
with one argument (the common
Table of Contents
Installation
This module is distributed via npm which is bundled with node and
should be installed as one of your project's dependencies
:
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) is available
via unpkg.com and exposed as ReactRenderCallback
.
<script src="https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js"></script>
Usage
API
renderCallback([ renderable [, props [, options ] ] ])
renders the given
renderable
withprops
// 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
for react types like class components, context provider or consumer, forward refs, factories, ... - invokes stateless function components (SFC) respecting their
defaultProps
- not using
React.createElement
for improved performance - except the SFC has
propTypes
andprocess.env.NODE_ENV
is notproduction
, in that caseReact.createElement
is used to enable typechecking with PropTypes
- not using
- gracefully handles other types like string, array, react elements, ...
props (optional): to pass to renderable
options (optional):
cloneElement
(default:false
, since: v1.1.0): allows to passprops
to the element usingReact.cloneElement
renderCallback(<a href="#bar">bar</a>, {title: 'foo'})
// --> <a href="#bar">bar</a>
renderCallback(<a href="#bar">bar</a>, {title: 'foo'}, {cloneElement: true})
// --> <a href="#bar" title="foo">bar</a>
returns
- the created react element
false
,null
,undefined
andtrue
are returned asnull
just like in JSX- the value as is for all other values
createRender([ renderable [, options ] ])
since: v1.1.0
Returns a function (
(...args) => ...
) to renderrenderable
with.
// 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
.
const renderCallback = createRender((a, b, c) => ({a, b, c}))
renderCallback(1, 2, 3)
// -> { a: 1, b: 2, c: 3 }
If the
renderable
has adefaultProps
property only the first parameter is used and merged with thedefaultProps
.
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.
Use options.cloneElement
This option allows to pass down
props
without to need to create a function within render which merges the defined and provided props.
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}) => (
<CountSeconds>
<DisplayValue prefix={prefix} />
</CountSeconds>
)
Use createRender
to pass down several arguments
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 = () => (
<CountSeconds>
{(value, reset) => (
<React.Fragment>
<DisplayValue prefix="Seconds: " value={value} />
<button onClick={reset} type="button">
reset
</button>
</React.Fragment>
)}
</CountSeconds>
)
Use createRender
to interop with a library which only supports functions as render-prop
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.props
return (
<div>
<button {...getTogglerProps()}>Toggle me</button>
<div>{on ? onLabel : offLabel}</div>
</div>
)
}
}
const ToggleView = createRender(Toggler)
const App = () => <Toggle>{ToggleView}</Toggle>
Other Solutions
Credits
A special thanks needs to go to Kent C. Dodds for his great video series ( egghead.io, frontendmasters.com and youtube.com). His projects are either used in this project (kcd-scripts) or are a template for the structure of this project (downshift). Make sure to subscribe to his newsletter.
Contributors
Thanks goes to these people (emoji key):
| Sascha Tandel💻 📖 🚇 ⚠️ 👀 📝 🐛 💡 🤔 📢 | | :---: |
This project follows the all-contributors specification. Contributions of any kind welcome!
LICENSE
MIT