babel-plugin-jsx-on-demand-children
Babel plugin/macro offering a pleasnt syntax for rendering children on demand.
!Build Statusbuild-badgebuild !Babel Macrobabel-plugin-macros-badgebabel-plugin-macros !Code Coveragecoverage-badgecoverage !versionversion-badgepackage !downloadsdownloads-badgenpmtrends !MIT Licenselicense-badgelicense
!PRs Welcomeprs-badgeprs !Code of Conductcoc-badgecoc
Introduction
A React component added to the tree will always evaluate all of its properties including the component body. A simple example of this (taken from jsx-control-statements) is attempting to implement a conditional component:<IfComponent condition={item}>
<Text>{item.title}</Text>
</IfComponent>
The error will be "Cannot read property 'title' of undefined", because React will evaluate the body of the custom component and pass it as "children" property to it. The only workaround is to force React into lazy evaluation by wrapping the statement in a function.
<IfComponent condition={item} render={() => (<Text>{item.title}</Text>)}></IfComponent>
This is precisely what this plugin/macro does, albeit with a slightly different syntax:
<AsyncHandler status={status}>
<JsxOnDemandChildren>
<AsyncHandler.Loading>...</AsyncHandler.Loading>
<AsyncHandler.Success>...</AsyncHandler.Success>
<AsyncHandler.Error>...</AsyncHandler.Error>
</JsxOnDemandChildren>
</AsyncHandler>
becomes:
<AsyncHandler
Loading={() => <AsyncHandler.Loading>...</AsyncHandler.Loading>}
Success={() => <AsyncHandler.Success>...</AsyncHandler.Success>}
Error={() => <AsyncHandler.Error>...</AsyncHandler.Error>}>
</AsyncHandler>
This is most useful for components written to take advantage of this plugin, in the example above the AsyncHandler
component could look like this:function AsyncHandler({status, Loading, Success, Error}) {
return (
{status === 'loading' && <Loading/>}
{status === 'success' && <Success/>}
{status === 'error' && <Error/>}
);
}
Installation
Option 1: As a macro (Recommended)
Installbabel-plugin-macros
and babel-plugin-jsx-on-demand-children
to your devDependencies
:npm install --save-dev babel-plugin-macros babel-plugin-jsx-on-demand-children
Add
babel-plugin-macros
to your babel configuration:Adding babel-plugin-macros to your configbabel-plugin-macros.config
Usage
If installed as a macro, import itimport JsxOnDemandChildren from 'babel-plugin-jsx-on-demand-children/macro'
// or
const JsxOnDemandChildren = require('babel-plugin-jsx-on-demand-children/macro')
Create your custom component, ie:
export default function Conditional({ condition, If, Else}) {
return condition ? (<If />) : (<Else />);
}
Conditional.If = function({children}) {
return <>{children}</>;
}
Conditional.Else = function({children}) {
return <>{children}</>;
}
Use with
<JsxOnDemandChildren>
:
import Conditional from './Conditional';
function SomeComponet() {
return (
<Conditional condition={isOk}>
<JsxOnDemandChildren>
<Conditional.If>
Everything is fine!
</Conditional.If>
<Conditional.Else>
We have a problem!
</Conditional.Else>
</JsxOnDemandChildren>
</Conditional>
);
}