compose-hooks

1.0.5 • Public • Published

🪢 compose-hooks 🪢

Make your React Components purely presentational, and simply bind the props for them in a declarative manner.

Why?

When I tried some different "compose hooks" libraries on npm, for each one I missed some feature or configurability. None of them supported the full control I felt required for all situations, so this version enables just a few key control features.

  • 0 dependencies, but of course React is a peer dependecy.

composeHooks

Overview

This HOC (Higher Order Component) wraps a component in order to attach hooks, props & behaviors.

It enables the separation of presentation from logic & behavior, like this:

// MyComp.jsx

const MyCompPresenter = ({ ...props }) => (
  <View>
    <Text>
      {`Here is the pure JSX content,`}
      {`which means these type of pure component functions Never have bodies, only direct returns of JSX.`}
      {`This is because all logic, hooks etc is bound via composeHooks and enter here as props.`}
      {`A good pattern is for these presenter components to always end in "...Presenter".`}
    </Text>
  </View>
);

export const MyComp = composeHooks({
  // Hooks and prop creations (See below)
})(MyCompPresenter);

Syntax & behavior

First and foremost:

  • Each value will be executed as a function at render.

Then, the composeHooks basically have 4 behaviors for the key-values in the object given to it:

  • Props from the parent will by default override the props from composeHooks.
  • A prefix > in the key string will inject all props up until that point into the value function.
  • A postfix ! in the key string will make this prop override that prop possibly coming from the parent.
  • The result of a value function call will be spread into props if the key string begins with use followed by a capital letter, as in e.g. useValue. (Otherwise the result will directly be assigned to the prop.)

Examples

Let's see some examples of what the key-values can be and look like.

export const MyComp = composeHooks({
  /* Simplest use. The hook returns an object that will be spread into props. */
  useExpanded,
  /* Hook returns something/anything that we want to assign to `theme` prop. */
  theme: useTheme,
  /* We can use a simple function to return a constant value, and... */
  noUppercase: () => true,
  /* ...with the `!` syntax overwrite the possible incoming prop with the same name. */
  'icon!': () => 'arrow-right',
  /* Same as above with an object put into `labelStyle` (and overriding parent prop). */
  'labelStyle!': () => ({ flex: 1 }),
  /* Putting a ">" first will inject all previous props into the function. Hence, we can use `theme` here. */
  '>color': ({ theme }) => theme.colors.onPrimary,
  /* Combine `>` & `!` to use incomming props and then overwrite.
  (This pattern is especially useful for `style`.) */
  '>style!': ({ theme, style }) => ({
    backgroundColor: theme.colors.onSurfaceVariant,
    ...style,
  }),
  /* If our custom hook `useCustomHook` needs some props, but we want the returned object to
  be spread into all final props, we can give it a dummy name that follows the naming convention
  of React Hooks. */
  '>useSpread': useCustomHook,
  /* Using e.g. ramda can be a nice point-free style way of selecting/using something from a hook call. */
  t: R.pipe(useTranslation, R.head),
})(MyCompPresenter);

A possible output (props for the Presenter) from the above composed hooks etc could be:

const MyCompPresenter = ({
  expanded,
  toggleExpanded,
  theme,
  noUppercase,
  icon,
  labelStyle,
  color,
  style,
  someValueFromCustomHook,
  anotherValueFromCustomHook,
  t,
}) => (
  // ...
);

Happy coding!

Licence

MIT

Package Sidebar

Install

npm i compose-hooks

Weekly Downloads

46

Version

1.0.5

License

MIT

Unpacked Size

12.1 kB

Total Files

5

Last publish

Collaborators

  • ez