Observing React, Preact and Inferno
This document focuses on React, but the same applies to Inferno and Preact
A Refract hook is available in version 2.3.0-alpha.0. API is similar except functions cannot be observed. For more detail, see useRefract API
Refract exposes an object called component
as your aperture
's first argument, which allows you to cause side-effects in response to changes within your React app.
This component
object contains three properties: observe
, mount
, and unmount
. The observe
property is a function which let you observe your React props. The mount
and unmount
properties are streams which let you observe your React component's lifecycle.
Example
The explanations below are all based on changing the aperture
in the following example to observe different things:
Observing Props
Refract's component.observe
function lets you observe your React props. It handles three different use cases: observing values, observing functions, and observing all props.
component.observe
takes two optional arguments:
propName
(string): an optional string, the name of the prop which you wish to observe.propTransformer
(function): an optional function to transform each received value ofpropName
When observing values, the returned stream is initialised with the current observed prop value. If you wish to only observe subsequent changes, you can "drop" the first value: search for a drop
operator in the reactive programming library you use.
Observing Values
Values are the primitive props you pass into your components: numbers, strings, booleans, objects, etc.
When the prop you observe is a value, component.observe
will return a stream of this prop's values as it changes over time.
Refract emits new prop values only if they have changed. The change detection is done using reference equality ===
- if you need a different change detection mechanism (to exclude more values), it is easy to filter them using a filter
operator.
For example, if we want to observe the value
prop in our aperture, and only cause an effect when the new string is at least five characters long:
Prop values can be transformed using the second argument of observe
, and only distinct values returned by the transformer will be emitted by the returned observable. It is handy for observing nested values:
Observing Functions
Functions are the callbacks you pass into your components: any function which is passed as props, such as an onClick handler or a setState function. By default, Refract will decorate these prop functions, so you can observe arguments they are called with. You can turn this off by setting decorateProps
to false
in withEffects
config object.
When the prop you observe is a function, component.observe
will return a stream which emits a new value each time your function is called. This value will be the first argument passed to the function.
For example, if we want to observe arguments passed to the onChange
prop to achieve the same effect as above:
This example does not significantly differ from the value
example above (the stream won't be initialised with a value), but in more complex situations it can be extremely useful to observe arguments passed to callbacks in addition to values passed via props.
If you want to observe a function taking multiple args, you can provide a second argument to observe
:
Observing All Props
In some cases, within your aperture
you might wish to use the current value of all your component's props. While this is possible via manually calling component.observe('prop')
for each of the props you wish to include and then combining all of the resulting streams, this is a lot of setup for a simple feature.
Instead, when you do not specify a propName
, component.observe
will return a stream which emits a new object each time any prop changes. This object will contain all of your component's props. (note: change detection in this case is determined by React: withEffects is implemented as a PureComponent)
For example, if you wanted to just send all props through to your handler
every time one of them changes:
Observing Events
In some cases you might want to observe a particular event such as a click on an hyperlink, without having a prop to observe. You might also want to use Refract for all your application mutations and effects, without piggy backing on existing mutations.
withEffects
injects a method pushEvent
to your components, so you can inform Refract of events happening inside your components. We use a callback because we aim to offer a universal solution not tied to a specific renderer (web, native). That way we don't have to use refs or low-level platform-specific primitives.
Pushing events
pushEvent
is a curried function which takes an event name (eventName
) and a value:
Observing events
In your aperture, you can observe events by simply invoking component.fromEvent
. It takes two arguments (second one is optional):
eventName
(string): the name of the event which you wish to observeeventTransformer
(function): an optional function to transform the value of eacheventName
event
Using events
A convenient helper function useEvent
is available on component
, to make it easier to use events: it returns a tuple containing the result of fromEvent(eventName)
and pushEvent(eventName)
. useEvent
takes two arguments:
eventName
(string): the name of the eventseedValue
(any): an optional seed value to initialise the stream of event values with
Observing Lifecycle Events
The remaining two properties on the component
object are component.mount
and component.unmount
.
These are streams which emit an event, like a signal, either when the component mounts or when the component unmounts.
Observing Component Mount
component.mount
is a stream which will emit a single value when a component mounts.
It can be useful to defer any logic until a component has been mounted.
Observing Component Unmount
component.unmount
is a stream which will emit a single value when a component unmounts.
It can be useful to trigger side-effects when a component is about to be unmounted.
Combining Observations
Refract's API is designed so that you have complete, fine-grained control over your side-effects. You are encouraged to observe multiple props simultaneously (both values and functions) alongside lifecycle events.
By combining these observable sources with the power of reactive programming, you can build complex side-effect logic in a clear and declarative fashion.
Last updated