A collection of Higher-Order Components for React, especially useful with Recompose.
A Higher-Order Component is a function that takes a component and returns a new component.
yarn add recompose @hocs/omit-props
omitProps(
...props: Array<string>
): HigherOrderComponent
import React from 'react';
import { compose, withProps } from 'recompose';
import omitProps from '@hocs/omit-props';
const Demo = (props) => (
<h1>props: {JSON.stringify(props)}</h1>
);
export default compose(
withProps({ a: 1, b: 2, c: 3 }),
omitProps('a', 'b')
)(Demo);
yarn start demo omit-props
Inspired by Reassemble, in comparison with Recompose lifecycle
this HOC provides a handy (and limited) way to use some of React Component Lifecycle methods such as:
onWillMount(props)
onDidMount(props)
onWillReceiveProps(props, nextProps)
onWillUpdate(props, nextProps)
onDidUpdate(prevProps, props)
onWillUnmount(props)
So no this
, setState
or even constructor
, you have no direct access to class instance anymore (:tada:).
yarn add recompose @hocs/with-lifecycle
withLifecycle(
methods: Object
): HigherOrderComponent
import React from 'react';
import { compose, withState } from 'recompose';
import withLifecycle from 'with-lifecycle';
const Demo = ({ isLoading }) => (
<h1>{ isLoading ? 'Loading' : 'Done' }</h1>
);
export default compose(
withState('isLoading', 'setLoading', false),
withLifecycle({
onDidMount({ setLoading }) {
setLoading(true, () => {
setTimeout(() => setLoading(false), 3000);
})
},
onWillUnmount() {
console.log('bye');
}
})
)(Demo);
In addition, it can handle a factory function which works like Recompose withHandlers
factory:
withLifecycle(
methodsFactory: (initialProps: Object) => methods: Object
): HigherOrderComponent
withLifecycle(
({ shouldLoadOnMount }) => {
if (shouldLoadOnMount) {
return {
onDidMount({ setLoading }) {
setLoading(true, () => {
setTimeout(() => setLoading(false), 1000);
})
}
};
}
}
)
yarn start demo with-lifecycle
As a bonus you can "share" stuff across different lifecycle methods in that factory scope with let mySharedStuff
, just like you did before with this.mySharedStuff
using a class instance.
yarn add recompose @hocs/debounce-handler
debounceHandler(
handlerName: string,
delay: ?number,
leadingCall: ?boolean
): HigherOrderComponent
import React from 'react';
import { compose, withState, withHandlers } fgrom 'recompose';
import debounceHandler from '@hocs/debounce-handler';
const Demo = ({ count, onButtonClick }) => (
<div>
<h1>{count}</h1>
<button onClick={onButtonClick}>CLICK ME FAST</button>
</div>
);
export default compose(
withState('count', 'setCount', 0),
withHandlers({
onButtonClick: ({ count, setCount }) => () => setCount(count + 1)
}),
debounceHandler('onButtonClick', 300)
)(Demo);
yarn start demo debounce-handler
yarn add recompose @hocs/throttle-handler
throttleHandler(
handlerName: string,
interval: ?number,
leadingCall: ?boolean
): HigherOrderComponent
import React from 'react';
import { compose, withState, withHandlers } fgrom 'recompose';
import throttleHandler from '@hocs/throttle-handler';
const Demo = ({ count, onButtonClick }) => (
<div>
<h1>{count}</h1>
<button onClick={onButtonClick}>CLICK ME FAST</button>
</div>
);
export default compose(
withState('count', 'setCount', 0),
withHandlers({
onButtonClick: ({ count, setCount }) => () => setCount(count + 1)
}),
throttleHandler('onButtonClick', 300)
)(Demo);
yarn start demo throttle-handler
- See how existing HOCs are done, especially their
package.json
files. - Create a new folder in
packages/
, let's saywith-foo
. - Put source code in
with-foo/src/
, it will be transpiled and bundled intowith-foo/dist/
,with-foo/lib/
andwith-foo/es/
. - Put tests written with Jest in
with-foo/test/
. - Put demo in
with-foo/demo/
, it will be rendered and wrapped with HMR. - See Start.
- Done.
yarn
yarn start build <package>
yarn start demo <package>
yarn start test
yarn start testWatch
yarn start lint