npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pqmcgill/cycle-react

v1.0.8

Published

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

Downloads

22

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 @cycle/dom, 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: Cycle.js Getting Started

Cycle React depends on your application already including two packages: React and React-Dom. Both at >= version 16.3

# installing peer dependencies
npm install --save [email protected]^ [email protected]^

To install Cycle React itself is simply

# 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.

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.

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.

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

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.

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/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)

{
  "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:

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:

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.

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,

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!