Pushing to Props
By now, you should have a better understanding of what Refract does:
Refract has three built-in effect handlers, to:
- Pass additional props to the child it wraps
- Replace props
- Render components
This section focuses on adding and replacing props, and its applications. All React, Preact and Inferno packages export two effect creators:
toProps
and asProps
. They both take an object of props.Note that by default, props passed to
toProps
and asProps
won't be merged with previous values: to enable this behaviour, you need to set mergeProps
to true
in withEffects
config.Any value emitted by your aperture which has been wrapped with
toProps
will cause the wrapped component to re-render with the additional provided props. Let's see a very simple example where a prop doubledValue
is computed from a prop value
:import React from 'react'
import { withEffects, toProps } from 'refract-rxjs'
import { map } from 'rxjs/operators'
const DoubleValue = ({ value, doubledValue }) => (
<div>Two times {value} is {doubledValue}</button>
)
const aperture = (component, { initialCount }) => {
component.observe('value').pipe(map(value => toProps({
doubledValue: 2 * value
})))
}
export default withEffects(aperture)(DoubleValue)
asProps
is used exactly like toProps
, except that the provided props will be the only ones passed to the child component.It allows you to fully control what props are passed through, and can result in performance benefits by controlling exactly when a component re-renders.
Essentially,
toProps
and asProps
allow you to inject data into components, by using existing props or external data sources (sideways data loading).With the ability to set component props and to listen to events (with
pushEvent
and component.fromEvent(name)
), comes the ability to handle state: events are the source of truth, and state is a projection of these events.The example below is a simple counter example: each time a button is clicked, the count is incremented. We use a reducer to persist state between events, and pass it as props. It will sound familiar if you've used Redux: we go from events to state to props, the same way Redux (with
connect
) goes from actions to state to props (see Replacing react-redux connect HoC recipe). Refract can be used to bind together state from multiple sources.Note the use of
component.useEvent(eventName)
which returns a tuple containing the result of fromEvent(eventName)
and pushEvent(eventName)
(and the use of startWith
to ensure the addOne
prop is passed to the component on initial render).import React from 'react'
import { withEffects, toProps } from 'refract-rxjs'
import { scan, startWith, map } from 'rxjs/operators'
const Counter = ({ count, addOne }) => <button onClick={addOne}>{count}</button>
const aperture = (component, { initialCount }) => {
const [addOneEvents$, addOne] = component.useEvent('addOne')
return addOneEvents$.pipe(
startWith({
count: initialCount,
addOne
}),
scan(({ count, ...props }) => ({
...props,
count: count + 1
})),
map(toProps)
)
}
export default withEffects(aperture)(Counter)
Last modified 4yr ago