# @pqmcgill/cycle-react

> A Cycle.js driver that treats React virtual DOM trees as sinks and pipes React events via sources

Latest version **1.0.8** (published 2018-06-10) · ISC license · 0 weekly downloads

## Install

```sh
npm install @pqmcgill/cycle-react
pnpm add @pqmcgill/cycle-react
yarn add @pqmcgill/cycle-react
bun add @pqmcgill/cycle-react
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.8 |
| Published | 2018-06-10 |
| First published | 2018-04-13 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 4 |
| Unpacked size | 410.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Patrick McGill |
| Maintainers | pqmcgill |
| Keywords | CycleJS, React |

## Links

- npm: https://www.npmjs.com/package/@pqmcgill/cycle-react
- npm.io page: https://npm.io/package/@pqmcgill/cycle-react

## Dependencies (4)

- [react](https://npm.io/package/react.md) ^16.4.0
- [xstream](https://npm.io/package/xstream.md) ^11.2.0
- [prop-types](https://npm.io/package/prop-types.md) ^15.6.1
- [@types/prop-types](https://npm.io/package/@types/prop-types.md) ^15.5.2

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 1.0.8 (latest) — 2018-06-10
- 1.0.7 — 2018-06-10
- 1.0.6 — 2018-05-24
- 1.0.5 — 2018-05-23
- 1.0.4 — 2018-04-16
- 1.0.3 — 2018-04-16
- 1.0.2 — 2018-04-15
- 1.0.1 — 2018-04-13
- 1.0.0 — 2018-04-13

## README

# cycle-react
Cycle React is a Cycle.js driver that renders React virtual dom elements via sinks, and emits React events via sources.

It is heavily inspired by <a href="https://cycle.js.org/api/dom.html">@cycle/dom</a>, and was built in an effort to provide the wonderful API of the DOM driver while simultaneously providing access to the rich ecosystem of React components.

Using Cycle React allows you to create hybrid Cycle/React applications while providing the best aspects of both worlds.

## Installation

These instructions assume that you already have an existing running Cycle.js application. If you don't, then follow this excellent documentation to get started: <a href="https://cycle.js.org/getting-started.html">Cycle.js Getting Started</a>

Cycle React depends on your application already including two packages: <a href="https://github.com/facebook/react">React</a> and <a href="https://github.com/facebook/react/tree/master/packages/react-dom">React-Dom</a>. Both at >= version 16.3
```bash
# installing peer dependencies
npm install --save react@16.3.0^ react-dom@16.3.0^
```

To install Cycle React itself is simply

```bash
# installing cycle-react
npm install --save @pqmcgill/cycle-react
```

You should now be set to use Cycle React

## Usage

Once you have all of the above packages installed, usage is quite simple.

### Setup

First you will want to import the function `makeReactDriver` from cycle-react. It takes either a document query selector or dom element as input, and returns a driver that renders your app into that element.

```javascript
import { run } from '@cycle/run';
import { makeReactDriver } from '@pqmcgill/cycle-react';
import Main from './Main';

const drivers = {
  React: makeReactDriver('#app')
};

run(Main, drivers);
```

### hyperscript h()

Cycle React provides a hyperscript function called `h()` that has the exact same signature as `React.createElement`. It takes three arguments: `tagName`, `props`, and `children`, and returns a `ReactElement`.

```typescript
h(tagName: string, props: Object, children...: Array<string | number | ReactElement>): ReactElement
```

The reason for the `h()` function is to process the props object passed into it prior to rendering in order to allow Cycle React to understand how to handle events as we'll see a little further down.

Using the `h()` function, we can create a stream of React VDom nodes.

```javascript
import xs from 'xstream';
import { h } from '@pqmcgill/cycle-react';

function Main(sources) {
  return {
    React: xs.of(
      h('div', {},
        h('p', {}, 'Follow this link to learn more about Cycle.js'),
       h('a', { href: 'https://cycle.js.org/' }, 'Cycle.js')
      )
    )
  };
}
```

The `h()` function will also render existing `React` `Components`

```javascript
import xs from 'xstream';
import { h } from '@pqmcgill/cycle-react';
import MyReactComponent from './MyReactComponent';

function Main(sources) {
  return {
    React: xs.of(
      h(MyReactComponent, { foo: 'bar' })
    )
  };
}
```

Most developers don't like working with the `h()` functions directly, which is why Cycle React offers hyperscript helper functions to make the code more legible.

```javascript
import xs from 'xstream';
import { div, a } from '@pqmcgill/cycle-react';

function Main(sources) {
  return {
    React: xs.of(
      div([
        p('Follow this link to learn more about Cycle.js'),
        a({ href: 'https://cycle.js.org/' }, 'Cycle.js')
      ])
    )
  };
}
```

You can even use `jsx`! Just point your jsx configuration to use the `h()` function.

### Babel
```jsx
/** @jsx/h */
import { h } from '@pqmcgill/cycle-react';

function Main(sources) {
  ...
  const view$ = xs.of(
    <div>
      <p>Sweet! I can use JSX!!!</p>
      <a href="https://cycle.js.org/">Seriously! Check out these docs</a>
    </div>
  );
  ...
}
```
### Typescript (.tsconfig.json)
```json
{
  "compilerOptions": {
    ...,
    "jsx": "react",
    "jsxFactory": "h"
  }
}
```

## Events

How Cycle React handles events is what makes this project unique. Normally, in a React project, you would make use of an imperative api for handling events. For example:

```jsx
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      clicked: false
    };
  }
  this.handleClick = (e) => {
    // imperatively do something with event
    this.setState(() => ({
      clicked: true
    }))
  }
  render() {
    return (
      <div>
        { this.state.clicked && <p>Clicked!</p> }
        <button onClick={ this.handleClick }>Click!</button>
      </div>
    )
  }
}
```

In Cycle React, you would write the same code in a more declarative style:

```jsx
import { h } from '@pqmcgill/cycle-react';

function MyComponent(sources) {
  // declaratively subscribe to events
  const click$ = sources.React
    .select('myBtn')
    .event('click')
    .map(e => true)
    .startWith(false);

  const view$ = click$.map(clicked => (
    <div>
      { clicked && <p>Clicked!</p> }
      <button selector="myBtn">Click!</button>
    </div>
  ));

  return {
    React: view$
  };
}
```

Notice the use of the `selector` prop. This prop is special and allows Cycle React to wire up the sources properly for subscribing to events. React Cycle provides a React object on the sources map. The React source has a public method `select(selector: string)` that will return an instance of `ReactSource`. `ReactSource` has a public method `event(eventType: string): Stream<any>`. The returned Stream from calling `event(eventType)` emits values when the corresponding prop named `on[EventType]` is called on the component with the `selector` prop. This provides an excellent means of interoperability between pure React Components and Cycle.js apps. 

The above code works because `button` has a prop named `onClick`. `onClick` is a built-in prop, but we're not limited to built-in props. Take the following example which uses an existing React Component with a props based callback API.

```jsx
class Timer extends React.Component {
  ...
  componentDidMount() {
    let count = 0;
    setTimeout(() => {
      this.props.onTick(count++);
    }, 1000);
  }
  ...
}

function Main(sources) {
  const tick$ = sources
    .select('timer')
    .event('tick')
    .subscribe({
      next(v) { console.log(v); }
    });

  return {
    React: xs.of(
      <Timer selector="timer" />
    )
  };
}
```

### Isolation

When using `@cycle/isolate` to provide a scope to a component, 

```jsx
isolate(MyComponent, 'scoped')(sources)
```

any cycle-react events that the component subscribes to will also be scoped to that component. This mitigates the risk for namespace collisions when using the selector prop, and allows for the same component to be reused multiple times on the same page.

### TODO: provide more detailed documentation for use with Typescript
### TODO: provide example usages in the src code

## Enjoy!

---
_Source: https://npm.io/package/@pqmcgill/cycle-react · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
