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.
props
case) aka Render Props aka Function as Child
or optional with several argumentsfalse
, null
, undefined
and true
are returned as null
just like in JSXThis 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>
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
React.createElement
for react types like
class components,
context provider or consumer,
forward refs,
factories, ...defaultProps
React.createElement
for improved performancepropTypes
and
process.env.NODE_ENV
is not production
, in that case React.createElement
is used to
enable typechecking with PropTypesprops (optional): to pass to renderable
options (optional):
cloneElement
(default: false
, since: v1.1.0): allows to pass props
to
the element using React.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
false
, null
, undefined
and true
are returned as null
just like in JSXcreateRender([ 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
A basic example showing the most common use cases can be viewed/edited at codesandbox.io.
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>
)
createRender
to pass down several argumentsclass 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>
)
createRender
to interop with a library which only supports functions as render-propimport 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