Convert between Render Props and HOC
Package | Version | Dependencies | DevDependencies | Build |
---|---|---|---|---|
rp-hoc |
Install from npm
:
npm install rp-hoc --save
Import:
import { toRP, withRP } from 'rp-hoc';
If you use decorator
with Babel please run this command:
npm install --save-dev babel-plugin-transform-decorators-legacy
And modify the .babelrc
file to enable the plugin:
{
"plugins": ["transform-decorators-legacy"]
}
Convert the decorator to a render-props component.
Options:
Option | Default value | Usage | Tests |
---|---|---|---|
renderKey | 'children' |
change the callback key in props. | test/hoc-to-rp/react-redux.js#L92-L117 |
useComponent | false |
Use React.Component to create new component instead of Stateless Component. |
test/hoc-to-rp/react-redux.js#L119-L149 |
usePureComponent | false |
Use React.PureComponent to create new component instead of Stateless Component. |
test/hoc-to-rp/react-redux.js#L151-L181 |
Example React Redux
Use decorator:
@connect(
mapStateToProps,
mapDispatchToProps,
)
class App extends Component {
render() {
const { counter, inc, dec } = this.props;
return (
<div>
<div id="counter">{counter}</div>
<button id="inc" onClick={() => inc()}>Increment</button>
<button id="dec" onClick={() => dec()}>Decrement</button>
</div>
);
}
}
Convert to render-props component:
const Connect = toRP(
connect(
mapStateToProps,
mapDispatchToProps,
),
);
const App = () => (
<Connect>
{({ counter, inc, dec }) => (
<div>
<div id="counter">{counter}</div>
<button id="inc" onClick={() => inc()}>Increment</button>
<button id="dec" onClick={() => dec()}>Decrement</button>
</div>
)}
</Connect>
);
Use different renderKey
:
const Connect = toRP(
connect(
mapStateToProps,
mapDispatchToProps,
), {
renderKey: 'myRender', // this line changed
},
);
const App = () => (
<Connect
// this line changed
myRender={({ counter, inc, dec }) => (
<div>
<div id="counter">{counter}</div>
<button id="inc" onClick={() => inc()}>Increment</button>
<button id="dec" onClick={() => dec()}>Decrement</button>
</div>
)}
/>
);
Convert the render-props component to a decorator.
Options:
Option | Default value | Usage | Tests |
---|---|---|---|
renderKey | 'children' | change the callback key in props. | test/rp-to-hoc/react-value.js#L31-L49 |
multiArgs | null | Convert callback arguments to Array . Otherwise callback props will be assigned with original props by Object.assign . |
test/rp-to-hoc/react-value.js#L31-L49 |
Example React Value
Use render-props component:
import Toggle from 'react-toggled';
const App = () => (
<Toggle defaultOn>
{({ on, getTogglerProps }) => (
<div>
<button {...getTogglerProps()}>Toggle me</button>
<div id="result">{on ? 'Toggled On' : 'Toggled Off'}</div>
</div>
)}
</Toggle>
);
Convert to heigher-order component:
const App = ({ on, getTogglerProps }) => (
<div>
<button {...getTogglerProps()}>Toggle me</button>
<div id="result">{on ? 'Toggled On' : 'Toggled Off'}</div>
</div>
);
const WithToggle = withRP(<Toggle defaultOn />);
const AppWithToggle = WithToggle(App);
Also support decorator
:
const WithToggle = withRP(<Toggle defaultOn />);
@WithToggle
class App extends Component {
render() {
const { on, getTogglerProps } = this.props;
return (
<div>
<button {...getTogglerProps()}>Toggle me</button>
<div id="result">{on ? 'Toggled On' : 'Toggled Off'}</div>
</div>
);
}
}
To prevent prop-types
warning, you can use withRP(component, props, options)
:
const WithToggle = withRP(Toggle, { defaultOn: true });
@WithToggle
class App extends Component {
render() {
const { on, getTogglerProps } = this.props;
return (
<div>
<button {...getTogglerProps()}>Toggle me</button>
<div id="result">{on ? 'Toggled On' : 'Toggled Off'}</div>
</div>
);
}
}