babel-plugin-jsx-on-demand-children

Allow JSX children to be rendered on demand.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
babel-plugin-jsx-on-demand-children
000.1.02 years ago2 years agoMinified + gzip package size for babel-plugin-jsx-on-demand-children in KB

Readme

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)

Install babel-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 it
import 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>
  );
}

LICENSE

MIT