render-prop helper to render anything (Functions, Components, Elements, ...)
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.
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.
- 📦 Super tiny (~650 bytes)
- 👌 Dependency free (except for Object.assign polyfill)
- 🔌 Just Works TM
- 🔮 Tree shaking friendly (ESM, no side effects)
- 📚 Well documented
- 💯 test coverage
- ☀️ supports React v0.14, v15 and v16
- 👪 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
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>
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
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
A basic example showing the most common use cases can be viewed/edited at codesandbox.io.
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>
)
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>
)
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>
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.
Thanks goes to these people (emoji key):
Sascha Tandel 💻 📖 🚇 |
---|
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT