vue-compose
Create awesome Vue HOCs
Installation
npm install --save vue-compose
Usage
;; const enhance = ; const enhanced = ;
API
HOC Creators
The following methods will create a new HOC that wraps the provided component.
mapProps
Object Component;
Maps the props into a new object. Any props that are not returned will not be passed into the base component.
;
withProps
mapper: propName: string: Object | any | Object Component;
Maps props into a new object. The returned object will be merged with the existing props.
; ;
defaultProps
defaults: Object Component;
Sets default values for any props that are currently undefined.
;
acceptProps
props: Object | Array<string> Component;
Adds additional props to the component's props option. This allows you to accept props that aren't expected by the base component.
;
withHandlers
listeners: handlerName: string: any Component;
Adds event listeners to the base component's v-on
attribute.
;
If you add a listener, that event won't propagate any further. If you want to intercept an event but still propagate it, you will need to re-emit the event:
;
Handlers can access eachother with the handle
prefix, meaning you can trigger one handler from another:
withPassive
listeners: handlerName: string: any Component;
Just like withHandlers
except the event is automatically propagated up.
withNativeHandlers
listeners: handlerName: string: any Component;
Adds native DOM even listeners to the component.
withData
data: name: string: prop?: string listener?: string handler?: any initialValue?: any | any Component;
Creates a stateful HOC with the specified data properties.
name
The name of the data property. Note that if this conflicts with an incoming prop, it will kill the prop.
prop
The name of the prop that the data will be passed into. By default it is the same as name
.
listener
The name of the event that will trigger the update handler. By default it is the same as name
.
handler
A function that handles updating the data value when the listener
event is emitted.
initialValue
The initial value for the data property. If it is a function, it will be evaluated when the HOC is instantiated.
Example with the default options:
;
withHooks
hooks: hookName: string: Function Component;
Adds hooks to the component, i.e. beforeCreate
, created
, mounted
, etc.
;
withClass
classes: any | any Component;
Adds classes to the base component.
withStyle
style: any | any Component;
Adds styles to the base component.
provide
provide: Object | Object Component;
Leverages Vue's provide/inject
functionality. Use in conjunction with the inject
method.
branch
boolean vNode falseFn?: vNode Component
Use an alternate render function based on a predecate function. For example, if you want to render a loading spinner based on a loading
prop. If you don't provide a falseFn
, it will fall back to using the component's original render function; this is the most common use case.
Note that you must use render functions, it is not possible to insert template syntax here. This does mean, however, that you can still use jsx
syntax.
Mutators
Mutators don't create a new HOC, but actually mutate the provided component with new attributes.
withComputed
computed: name: string: Function Component;
Adds computed properties to the component.
withMethods
methods: name: string: Function Component;
Adds methods to the component.
setName
name: string Component;
Sets the name of the component.
inject
inject: Array<string> | Object Component;
Injects data into the component provided by provide
.
Utilities
compose
...hocCreators: Array<Function> Component;
Chain multiple HOCs together. Compose will combine the HOCs from right-to-left (or bottom-to-top). The result is a function that accepts a Component that will then be applied to all of the HOCs.
componentFromProp
propName: string | Component Component;
Creates a component using the provided prop value. The prop can either be a string - such as 'input'
or a component.
const C = ;
You can then use it like:
or:
componentFromSlot
componentOptions?: Object Component;
Creates a component that just outputs its slot content. This is useful if you want to apply styles etc. through a component, but don't want to render additional html elements.
Any props passed to this component will be passed through to the slot component.
NOTE: This is still an experimental feature and should be used with caution.
A couple of important notes:
- There must only be one root element inside the compponent
- For multiple root elements, use a
<template>
const enhance = ;const C = ;
I will now have someExtraClass and a width of 400px
createSink
void Component;
Creates a sink component. This component does not render anything, or take any configuration options, but calls fn
at render time. The props
parameter contains all props
and attrs
passed into the component.
The createSink method is useful when unit testing your compose
functions.
; ;
renderNothing
Component
A component that never renders.
; components: NotFinishedYet: renderNothing template: '<div><not-finished-yet/></div>'
You can also use this in a branch to only render under certain conditions:
MyComponent
FAQ
Why is recompose.X missing?
React and Vue look very similar on the surface, but they are actually entirely different beasts. Vue handles a lot more stuff behind the scenes. It's quite easy for React developers to want to shoehorn React techniques into a Vue application, but often there is no need because Vue handles things differently.
A couple of examples:
withPropsOnChange
,pure
,onlyUpdateForKeys
- because of it's functional nature, React needs a bit of help deciding whether or not re-render components. This isn't something that Vue suffers with because of its reactive nature, it's already able to work out whether a component is dirty.renameProp
,flattenProp
- React's props are super flexible, meaning you can accept any random assortment of props and then reorganise them before passing them into the next component. Vue requires all props to be defined upfront (so it can watch them), so chances are the props will already be named correctly, and if you want to accept props under different names etc. you have to explicitly add them to the component withacceptProps
.
Why isn't withHandlers wrapped in a closure?
Recompose's withHandlers
accepts a function that returns the handler function. This means you have access to the component's props via a closure. Vue is predominantly OOP orientated (see below) so there is no need to wrap props in a closure as you can access them with this.myProp
or this.$props.myProp
.
Why are there not more functional HOCs?
Context! Vue is not really written for functional components, and although you can set the functional
flag on a component, you still don't get a truly functional component in the React sense. Your render function still receives a context
object with properties of the current state of the component. On top of that you lose a lot of Vue's awesome features like computed properties that make memoization totally unecessary. And finally, it is a lot harder to pass non-prop options through multiple functional hocs, because the entire context is not retained.
How can I use this with Vuex?
Easily. You can easily combine vue-compose with vuex's helper functions:
const enhance = ;