react-render-callback v1.2.5
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
propscase) 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,undefinedandtrueare returned asnulljust 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-callbackThis 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
renderablewithprops
// 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.createElementfor react types like class components, context provider or consumer, forward refs, factories, ... - invokes stateless function components (SFC) respecting their
defaultProps- not using
React.createElementfor improved performance - except the SFC has
propTypesandprocess.env.NODE_ENVis notproduction, in that caseReact.createElementis 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 passpropsto 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,undefinedandtrueare returned asnulljust like in JSX- the value as is for all other values
createRender([ renderable [, options ] ])
since: v1.1.0
Returns a function (
(...args) => ...) to renderrenderablewith.
// 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
renderablehas adefaultPropsproperty 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
propswithout 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