drx v0.11.1
Dr. X
Declarative React Experiments
Install
npm install --save drxLet's see the example right away pls
Q. Is this ready to use in production?
Nope! Things are most likely going to change.
Q. What is this? Is it even a good idea?
I'm still figuring that out :D But I'm discovering a lot of useful patterns arising from this idea of writing components (structure & logic) declaratively.
In short, the goal is to provide a way of creating components by describing the dependencies between their props.
Take a look at the examples below if you're keen, and let me know what you think.
Getting started
Let's start with the simplest possible example:
import x from 'drx'
export default x({
className: 'message',
children: ''
})This is the rough equivalent of:
import React, { PureComponent } from 'react'
export default class extends PureComponent {
render () {
const { children, className } = this.props
return (
<div className={className || 'message'}>
{children}
</div>
)
}
}So we saved a few lines by using drx. That won't always be the case, sometimes we'll end up with more lines than a traditional approach. But I hope we can get to the point of gaining much more value from those extra lines.
Example: translating props
A common bit of display logic in components is translating props from a parent to a child. For example, this component receives an imageUrl prop which becomes the src of a child image element:
import React, { PureComponent } from 'react'
export default class extends PureComponent {
render () {
const { children, imageUrl } = this.props
return (
<div className='message'>
{ imageUrl && <img src={imageUrl} className='message__image' /> }
<h1 className='message__heading'>{props.heading || 'Default Heading'}</h1>
<span className='message__text'>{ children }</span>
</div>
)
}
}There are 3 prop translations happening in the example above:
imageUrlbecomes thesrcof the imageheadingbecomes thechildrenof the h1 (with fallback to a default value)childrenbecomes thechildrenof the span
We've also got some display logic to say we don't want to render an <img> element if we don't have an imageUrl.
To write the above with drx we'll get something like this:
import x from 'drx'
const Root = x({
className: 'message',
imageUrl: '',
children: '',
heading: 'Default Heading'
})
const Image = x.img({
className: 'message__image',
src: Root.imageUrl
})
const Heading = x.h1({
className: 'message__heading',
children: Root.heading
})
const Text = x.span({
className: 'message__text',
children: Root.children
})
Root.children(
Heading,
props => props.imageUrl && Image,
Text
)
export default RootReading from the top:
a component
Root, with some default propsa component
Image- renders an
<img>with classnamemessage__image - maps the
Root.imageUrlprop to thesrcattribute of the<img>
- renders an
a component
Heading- renders an
<h1>with classnamemessage__heading - maps the
Root.headingprop to the heading'schildren. If noheadingprop is provided toRoot, we'll get the default heading value fromRoot's definition.
- renders an
a component
Text- renders a
<span>with classnamemessage__text - adopts the
childrenof theRootcomponent as its ownchildren
- renders a
finally we tell
Rootto render withHeading,ImageandTextas its childrenImagewill only be rendered if we have a truthyimageUrlprop
Example: reducing props
Sometimes a child's prop is a function of 1 or more parent props. We can declare this with x.from. It both defines the dependency (ensuring that the props are passed down) and calls the function to transform or reduce the original values.
import x from 'drx'
const Root = x({
caption: '',
imageUrl: '',
secure: false
})
const Text = x.div({
children: x.from(Root.caption, p => p.caption.toUpperCase())
})
const Image = x.img({
alt: Root.caption,
src: x.from(
Root.imageUrl, Root.secure,
p => `${p.secure ? 'https' : 'http'}://example.com/${p.imageUrl}`
)
})
export default Root.children(
Image,
Text
)