compose-hooks-react v1.1.3
React Hooks Compose
React hooks are nice. They solve some issues with functional components like
using state and lifecycle methods. However, they also tend to tightly couple
hooks to React components. This leads to less composability of components,
more difficulty and complexity in unit testing components. This library allows
you to pass your hooks to your component. It also allows your hooks to compose
and by attaching what is returned from each hook to the overall props that are
passed to the next hook.
Note there is also a compose.d.ts file that has typings for composeHooks so
that you can use this package withing a TypeScript project without any additional
dependencies for @types.
Basic Usage
The compose function takes in an arbitrary amount of React hooks or you could just
use any functions you want. It calls them from left-to-right/top-to-bottom.
The preferred way is to have your hooks return an object with key/value pairs, but this
is not completely necessary. This way you can access the returned vales from props. However,
if you return something like a single value or an array ([someState, setSomeState]) it will
use the name of the hook/function as the key on props to access that value.
import React from 'react';
import composeHooks from 'react-compose-hooks';
const useFirstName = () => 'Jeremy';
const useLastName = () => ({ lastName: 'Pivens' });
const useFullName = props => ({ fullName: `Sir ${props.useFirstName} ${props.lastName}` });
export const TestComponent = ({ fullName }) => (<p>Hello, { fullName }</p>);
export const Composed = compose(
useFirstName,
useLastName,
useFullName,
)(TestComponent);
export default Composed;Notice a few things here. We can separately export our component without
it being coupled to any hooks at all. As long as in the end we pass in a fullName on props
that's all the component needs. We can no write unit tests very easily for this component.
Maybe it uses redux and connect? Maybe it uses hooks or maybe it using something completely
different. Doesn't matter. And we can export our composed version as well.
Notice that useFullName accesses props which are values computed by previous hooks. The hooks
must be passed into compose in an order were the output will be piped to the next function.
If we changed the above code to
export const Composed = compose(
useFullName,
useFirstName,
useLastName,
)(TestComponent)Then useFullName will not be able to access any props or values from the other hooks.
Although it will still have access to any props that are passed to the component. Lastly,
notice that 2 of the hooks were returning objects. This is nice because it is the same type as
props for components. However, notice in useFullName we access props.useFirstName for the value
that was returned by the useFirstName hook. Whenever a hook exports any value other than an Object
composeHooks will try to use the Function.name as the key on the props object.
You can compose hooks that use hooks including async hooks and useState, useContext, useEffect, etc.