Cycle React
Interoperability layer between Cycle.js and React
- Use React (DOM or Native) as the rendering library in a Cycle.js app
- Convert a Cycle.js app into a React component
- Support model-view-intent architecture with isolation scopes
npm install @cycle/react
Example
;;; { const inc = Symbol; const inc$ = sourcesreact; const count$ = inc$; const vdom$ = count$; return react: vdom$ ;} const App = ; ;
Other examples:
Read also the announcement blog post.
Usage
Installation (click here)
Install the package:
npm install @cycle/react
Note that this package only supports React 16.4.0 and above. Also, as usual with Cycle.js apps, you might need xstream
(or another stream library).
Use React as the rendering library (click here)
Use the hyperscript h
function (from this library) to create streams of ReactElements:
{ const vdom$ = xs; return react: vdom$ }
Alternatively, you can also use JSX or createElement
:
import xs from 'xstream' { const vdom$ = xs; return react: vdom$ }
However, to attach event listeners in model-view-intent style, you must use h
which supports the special prop sel
. See the next section.
Listen to events in the Intent (click here)
Use hyperscript h
and pass a sel
as a prop. sel
means "selector" and it's special like ref
and key
are: it does not affect the rendered DOM elements. Then, use that selector in sources.react.select(_).events(_)
:
{ const increment$ = sourcesreact const count$ = increment$ const vdom$ = count$ return react: vdom$ }
The sel
can be a string or a symbol. We recommend using symbols to avoid string typos and have safer guarantees when using multiple selectors in your Cycle.js app.
Pass event handlers as props to react components (click here)
Use hyperscript h
and pass a sel
as a prop. Use that selector in sources.react.select(sel).events(whatever)
to have cyclejs/react pass an onWhatever
function to the react component:
;;; // React component { return <div> <h1>Hello propsname</h1> <button onClick= props > press me </button> </div> ;} // Cycle.js component that uses the React component above { const click$ = sourcesreact ; const vdom$ = click$; return react: vdom$ ;} const Component = ;ReactDOM;
Isolate event selection in a scope (click here)
This library supports isolation with @cycle/isolate
, so that you can prevent components from select
ing into each other even if they use the same string sel
. Selectors just need to be unique within an isolation scope.
{ const elem$ = xs return react: vdom$ } { const childSinks = sources const click$ = sourcesreact const elem$ = childSinksreact return react: elem$ }
(Easy) Convert a Cycle.js app into a React component (click here)
Use makeComponent
which takes the Cycle.js main
function and a drivers
object and returns a React component.
const CycleApp = ;
Then you can use CycleApp
in a larger React app, e.g. in JSX <CycleApp/>
. Any props that you pass to this component will be available as sources.react.props()
which returns a stream of props.
If you are not using any other drivers, then you do not need to pass the second argument:
const CycleApp = ;
(Advanced) Convert a Cycle.js app into a React component (click here)
Besides makeComponent
, this library also provides the makeCycleReactComponent(run)
API which is more powerful and can support more use cases.
It takes one argument, a run
function which should set up and execute your application, and return three things: source, sink, (optionally:) events object, and dispose function.
run: () => {source, sink, events, dispose}
As an example usage:
const CycleApp = ;
source is an instance of ReactSource from this library, provided to the main
so that events can be selected in the intent.
sink is the stream of ReactElements your main
creates, which should be rendered in the component we're creating.
events is a subset of the sinks, and contains streams that describe events that can be listened by the parent component of the CycleApp
component. For instance, the stream events.save
will emit events that the parent component can listen by passing the prop onSave
to CycleApp
component. This events
object is optional, you do not need to create it if this component does not bubble events up to the parent.
dispose is a function () => void
that runs any other disposal logic you want to happen on componentWillUnmount. This is optional.
Use this API to customize how instances of the returned component will use shared resources like non-rendering drivers. See recipes below.
Recipe: from main and drivers to a React component (click here)
Use the shortcut API makeComponent
which is implemented in terms of the more the powerful makeCycleReactComponent
API:
; { return ;}
Recipe: from main and engine to a React component (click here)
Assuming you have an engine
created with setupReusable
(from @cycle/run
), use the makeCycleReactComponent
API like below:
{ return ;}
Recipe: from source and sink to a React component (click here)
Use the makeCycleReactComponent
API like below:
{ return ;}
License
MIT, Copyright Andre 'Staltz' Medeiros 2018