{"id":27696267,"url":"https://github.com/vasilioruzanni/react-cycle-connect","last_synced_at":"2025-04-25T15:09:22.063Z","repository":{"id":57118157,"uuid":"122765370","full_name":"VasilioRuzanni/react-cycle-connect","owner":"VasilioRuzanni","description":"Bring Cycle.js dataflows and side effect control to React.","archived":false,"fork":false,"pushed_at":"2020-01-25T15:26:18.000Z","size":135,"stargazers_count":8,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-25T15:09:16.012Z","etag":null,"topics":["cyclejs","functional-programming","javascript","react","reactive-programming","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VasilioRuzanni.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-24T18:01:08.000Z","updated_at":"2019-11-15T08:57:57.000Z","dependencies_parsed_at":"2022-08-22T19:50:23.621Z","dependency_job_id":null,"html_url":"https://github.com/VasilioRuzanni/react-cycle-connect","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VasilioRuzanni%2Freact-cycle-connect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VasilioRuzanni%2Freact-cycle-connect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VasilioRuzanni%2Freact-cycle-connect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VasilioRuzanni%2Freact-cycle-connect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VasilioRuzanni","download_url":"https://codeload.github.com/VasilioRuzanni/react-cycle-connect/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250840608,"owners_count":21495910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cyclejs","functional-programming","javascript","react","reactive-programming","typescript"],"created_at":"2025-04-25T15:09:21.335Z","updated_at":"2025-04-25T15:09:22.027Z","avatar_url":"https://github.com/VasilioRuzanni.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-cycle-connect\n\nAn experimental library that allows using [Cycle.js](https://cycle.js.org/) as a reactive dataflow framework for [React](https://reactjs.org/). \nWritten in TypeScript.\n\nThis little thing allows to define your app's **view** layer using regular React components, but implement the actual logic behind it using pure functional reactive approach, taking advantage of Cycle.js' [Model-View-Intent](https://cycle.js.org/model-view-intent.html) pattern and its exceptional **side effect control**.\n\nThis isn't a custom implementation of Cycle **pattern** for `React` but a link to real Cycle.js instead, so any Cycle.js drivers and wrappers can be applied (e.g., `cycle-onionify` for state management). Also, for this reason, some knowledge about how `Cycle.js` works is assumed.\n\n\u003e **Note:** This is an experimental lib and currently works with `React` and `xstream` only. If all goes good, the support for `preact`/`inferno` (instead of `React`) and for `RxJS`/`most` (instead of `xstream`) is anticipated. Nothing prevents from having `react-native` covered too.\n\n\u003e **UPDATE (MAR 2018):** Some internals overhaul is pending and it's currently waiting for Cycle.js to settle on hybrid push-pull reactivity and have internals rewritten to use [Callbags](https://github.com/callbag/callbag) instead of `xstream`. So, `react-cycle-connect` is going to be using Callbags by default too.\n\n**Any feedback is highly appreciated!**\n\n\n## Table of Contents\n\n- [Shut up and show me the code](#shut-up-and-show-me-the-code)\n- [Installation](#installation)\n- [Motivation](#motivation)\n  - [Why not just use Cycle.js alone?](#why-not-just-use-cyclejs-alone)\n  - [Is it a \"Cycle.js in React\" or \"React in Cycle.js\"?](#is-it-a-cyclejs-in-react-or-react-in-cyclejs)\n- [How it works (architecture)](#how-it-works-architecture)\n  - [Differences from idiomatic Cycle.js usage](#differences-from-idiomatic-cyclejs-usage)  \n- [Guide](#guide)\n  - [Basics](#basics)\n  - [Root Cycle](#root-cycle)\n  - [`render` option](#render-option)\n  - [`displayName` option](#displayname-option)\n  - [Inside the Cycle](#inside-the-cycle)\n    - [Drivers](#drivers)\n    - [Wrappers](#wrappers)\n    - [Sources](#sources)\n    - [Sinks](#sinks)\n  - [React `props`](#react-props)\n  - [Interactions](#interactions)\n    - [Events triggering by the view](#events-triggering-by-the-view)\n    - [View events handling with `interactions` source](#view-events-handling-with-interactions-source)\n    - [Upstream interactions with `interactions` sink (calling callbacks on `props`)](#upstream-interactions-with-interactions-sink-calling-callbacks-on-props)\n  - [React component lifecycle streams](#react-component-lifecycle-streams)\n  - [Side effect control and `fnCallEffect` driver](#side-effect-control-and-fncalleffect-driver)\n  - [Isolation](#isolation)\n    - [Naive explicit isolation (conceptually incorrect)](#naive-explicit-isolation-conceptually-incorrect)\n    - [`isolate` option for `cycleConnect()`](#isolate-option-for-cycleconnect)\n    - [`isolate` prop](#isolate-prop)\n    - [`\u003cIsolator\u003e` helper component](#isolator-helper-component)\n  - [Extra: state management with `cycle-onionify`](#extra-state-management-with-cycle-onionify)\n    - [`\u003cStateIsolator\u003e` helper component](#stateisolator-helper-component)\n    - [Handling collection state manually](#handling-collection-state-manually)\n    - [`\u003cCollection\u003e` helper component](#collection-helper-component)\n    - [`makeFilteredListLens()` factory function to assist `\u003cCollection\u003e`](#makefilteredlistlens-factory-function-to-assist-collection)\n  - [Testing](#testing) [WIP]\n  - [TypeScript support](#typescript-support) [WIP]\n- [API reference](#api-reference) [WIP]\n- [Alternatives / Competitors](#alternatives-competitors)\n  - [cycle-react](#cycle-react)\n  - [recycle.js](#recyclejs)\n  - [redux-cycles](#redux-cycles)\n- [FAQ](#faq) [WIP]\n\n\n## Shup up and show me the code\n\nCycle.js's [counter](https://github.com/cyclejs/cyclejs/tree/master/examples/basic/counter) example ported over:\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport xs from 'xstream';\nimport { run } from '@cycle/run';\nimport { cycleConnect } from 'react-cycle-connect';\n\n// Your Cycle.js `main` function\n\nfunction main(sources) {\n  const action$ = xs.merge(\n    sources.interactions.decrement.map(ev =\u003e -1),\n    sources.interactions.increment.map(ev =\u003e +1)\n  );\n  const count$ = action$.fold((acc, x) =\u003e acc + x, 0);\n\n  return {\n    props: count$.map(count =\u003e ({ count }))\n  };\n}\n\n// Your React component\n\nfunction App({ interactions, count }) {\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={interactions.decrement}\u003eDecrement\u003c/button\u003e\n      \u003cbutton onClick={interactions.increment}\u003eIncrement\u003c/button\u003e\n      \u003cp\u003eCounter: {count}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n\n// Some connection magic\n\nconst ConnectedApp = cycleConnect(main, {\n  root: true,\n  runFn: run\n})(App);\n\n// Render normally as it's a regular React app\n\nReactDOM.render(\n  \u003cConnectedApp /\u003e,\n  document.getElementById('root')\n);\n```\n\nAlso - there's official [TodoMVC](https://github.com/VasilioRuzanni/react-cycle-connect/tree/master/examples/todomvc) example with `cycle-onionify` for state management.\n\n\n## Installation\n\nUsing [npm](https://www.npmjs.com/):\n\n    $ npm install --save react-cycle-connect\n\nUsing [yarn](https://yarnpkg.com):\n\n    $ yarn add react-cycle-connect\n\n\n## Motivation\n\nThe motivation to create this lib was based off the need to retain the React-style composability of the **view** layer using regular React components, reuse existing React components, make it (the lib) easily/incrementally adoptable in an ongoing React project, but also take advantage of the Cycle.js' [MVI](https://cycle.js.org/model-view-intent.html) pattern and side effect control.\n\nAt the same time, while the most valuable thing from `Cycle` is the **pattern** itself, there are numerous available libs/plugins for Cycle.js to take advantage of, letting us take the best of both worlds.\n\nThis way, you can still use anything from React stack (e.g., `react-router` to compose your routed app screens), but describe the interactions as a dataflow, with pure functions and reactive streams. Most of React components are going to be [\"dumb\"](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) (and also [stateless functional](https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc) aka SFC) since all the backing logic and cross-component communication would be handled by a tree of `Cycle.js` programs.\n\n\n### Why not just use Cycle.js alone?\n\nThat is what I'd recommend considering in the first place. Its fast, its cool, the `snabbdom` (virtual DOM rendering engine behind Cycle's DOM driver) is goddamn fast and reliable. If you don't intend to use `React` components in any way, don't even get bothered. The `react-cycle-connect` is more about \"introducing Cycle.js to `React`\", not the other way around.\n\n\n### Is it a \"Cycle.js in React\" or \"React in Cycle.js\"?\n\nMore of a \"Cycle.js in React\". The app is bootstrapped by rendering a React component to the DOM, view is composed the React way. The root Cycle.js program is being `run` by rendering a root `cycleConnect()`ed component. **Though**, it doesn't prescribe how you write your Cycle.js programs, and aside from the DOM generation part, its just Cycle.js all the way.\n\n\n## How it works (architecture)\n\nEvery `cycleConnect()`ed component got a real Cycle.js program \"attached\" to it. The boundary between the two is `props`. From your Cycle.js program standpoint, **`props` is a view**. Cycle.js program can update `props` that React component will then render.\n\nA bunch of nested React components in your app represent a \"tree of React components\". `react-cycle-connect` maintains a \"tree of Cycle.js programs\" that map to `cycleConnect()`ed components and takes advantage of React's [context](https://reactjs.org/docs/context.html) feature to provide links between the nodes. Each connected component provides scoped links to the children nodes .\n\nNew \"Cycle nodes\" are attached lazily, upon associated React component initialization (this is where React controls how Cycle programs are run). The above-mentioned \"link\" is just an object on React `context` that brings couple properties:\n\n- `sources` for the child connected component's `main` function; and\n- `sinkProxies` to subscribe to that component's `main` function `sinks`.\n\nThis is where something unusual for the Cycle.js happens - we subscribe to and unsubscribe from connected component's `main` function `sinks` based on React component's lifetime hooks. In Cycle.js, you normally just run the app at startup and let it run as an ongoing process. But this is where `react-cycle-connect` performs the sync between the two worlds.\n\nOverall, aside from using React `context` (which is just an implementation detail) and some intense wrapping on the `react-cycle-connect` side to make laziness possible, `react-cycle-connect` tries to represent the entire tree of Cycle.js programs as close as possible to what you'd end up with by writing idiomatic Cycle.js with explicit calling of nested component's `main` functions from the parent component `main` function. The result of children components is always `merge`d.\n\nAside from passing the `sources` to children components, `react-cycle-connect` also explicitly applies some internal wrappers to integrate with React component: [`lifecycle`](#react-component-lifecycle-streams), [`props`](#react-props) and [`interactions`](#interactions), that are **scoped to a connected component's Cycle.js program only**. It also explicitly runs the internal [`fnCallEffect`](#side-effect-control-and-fncalleffect-driver) driver for the `root` nodes by default - this is necessary for the `interactions` sink to work (because its supposed to run callbacks passed via `props` and that might be an effectful function).\n\nNote that the entire internal \"tree\" of Cycle.js programs is maintained pure, including internal component-scoped wrappers, just as you would do with regular Cycle.js program.\n\n\n### Differences from idiomatic Cycle.js usage\n\n\u003e Note: there's a difference in how'd you write the `react`/`react-cycle-connect` app vs pure `Cycle.js` app. There's _no misuse_ of Cycle.js per se, we just don't use it for rendering with `react-cycle-connect` - and that applies certain implications to the approach.\n\n`React` and `Cycle.js`, while both allow to create user interfaces, imply different approaches to the app architecture. The most important part here is that they are conceptually different when it comes to generating the VDOM.\n\nIn order to combine the two approaches nicely, there are certain deviations from how'd you write the `Cycle.js`-only app to allow for more optimal React DX.\n\n- The main difference from a pure `Cycle.js` way is that its not a Cycle program that technically generates VDOM - instead, there's React component to represent a piece of UI. `Cycle.js` approach to view/`DOM` event handling is rather purist - view only defines the markup and nothing else (i.e., user interaction/event handlers are defined inside Cycle program itself and not as some view component `onClick`/etc attribute). That is not a crazy random opinion but instead a very well thought and weighted out decision by Cycle.js team. `react-cycle-connect` takes a different approach, which isn't that strict and is more in line with React, with callbacks amongst `props` and all that stuff. It enables the events/component callbacks handling via [interactions](#interactions).\n\n- The view composition is obviously completely different. In `Cycle.js` you run each component's `main` function that (possibly) generates a VDOM node and then explicitly combine the pieces of markup into a single VDOM stream that is then given to a DOM driver. With `react-cycle-connect` you compose the view layer with React components normally. You can just connect those to Cycle.js program to \"outsource\" the actual logic to it.\n\n\n## Guide\n\nThis assumes the preliminary knowledge of both `React` and `Cycle.js` (and `xstream`). It doesn't provide much of the insight on how these work, but is instead focused on how `react-cycle-connect` combines the two.\n\n\n### Basics\n\nThe result of `cycleConnect()` call is a [HOC](https://reactjs.org/docs/higher-order-components.html#convention-maximizing-composability) that optionally takes a React component (similar to that `connect()` function of `react-redux`) and returns a component that is _augmented_ with backing Cycle.js program. This Cycle.js program is internally wrapped into a \"Cycle Node\" that, when initialized, is connected to a tree of Cycle.js programs. \"Cycle Nodes\" of every `cycleConnect()`ed components are linked together via React `context`.\n\nNote, though, that there are no direct references from one component's Cycle program to another component's Cycle program, i.e., you're not invoking one `main` function from the other (this is perfectly possible though, but since we're not using `DOM driver` here, it would only handle non-DOM stuff). Instead, `react-cycle-connect` handles the linking behind the scenes, so the \"sibling\" Cycle programs are fed with the same `sources` and subscribe their `sinks` to the same `sinkProxies`.\n\nThere's essential concept of **isolation** in Cycle.js, so every `cycleConnect()`ed component accepts an [`isolate`](#isolate-prop) prop, that is directly passed to `isolate` function from `@cycle/isolate` package. Read more about Cycle.js isolation [here](https://cycle.js.org/api/isolate.html).\n\n\n### Root Cycle\n\nEvery `cycleConnect()`ed component provides a `cycleNodeLink` object to its children through React `context` and also expects that `cycleNodeLink` from some parent component (not necessarily immediate parent).\n\nThat link object has the following shape:\n```js\n{\n  // Sources to provide to our Cycle.js program's `main` function as an argument\n  sources: { ... },\n\n  // sinkProxies to subscribe to our Cycle program's `main` function sinks\n  sinkProxies: { ... }\n}\n```\n\nYou shouldn't be working with that directly but its important that something needs to provide the top-level `sources` and `sinks` in the first place. This is what `root` option of cycle connect for.\n\nAlso, the `cycleConnect()`ed components' programs (`main` functions) are lazily attached to already running upper-level Cycle.js program, so the `root` program has to be `run`.\n\nSo, root `cycleConnect`, aside from `{ root: true }` option, also needs `runFn` defined, so that it knows how to run your top-level Cycle.js program. This would normally be just a `run` function from `@cycle/run` package (or `@cycle/rxjs-run`, or `@cycle/most-run`, depending on the reactive streams library in use).\n\nYou could just `cycleConnect()` your top-level `App` component like we did in the [first example](#shut-up-and-show-me-the-code):\n \n```js\nimport { run } from '@cycle/run';\nimport { cycleConnect } from 'react-cycle-connect';\n...\n\nfunction main(sources) {\n  ...\n}\n\nfunction App() {\n  return (\n    // Some JSX\n    ...\n  );\n}\n\nconst ConnectedApp = cycleConnect(main, {\n  root: true,\n  runFn: run\n})(App);\n```\n\nThough this will work, its advisable to create a specialized `RootCycle` component just for this purpose:\n\n```js\n// RootCycle.js\n\nimport { run } from '@cycle/run';\nimport { cycleConnect } from 'react-cycle-connect';\n\nfunction main(sources) {\n  ...\n}\n\nexport const RootCycle = cycleConnect(main, {\n  root: true,\n  runFn: run\n})(); // No component to wrap? Its okay, read ahead\n\nexport default RootCycle;\n```\n\nThe top-level Cycle sources are actually `drivers` and `wrappers`, so root Cycle is also in charge of providing these `drivers` and `wrappers` to any Cycle.js program down the tree, as `sources`.\n\n`drivers` option is the object with keys defining properties of the `sources` object, identical to how you'd do that in a regular Cycle.js program.\n\n`wrappers` option accepts an array of wrappers (order might matter there, so its a user-land option).\n\nAlso, the `main` function is optional (because you might need a `cycleConnect` to be a `root` or for `isolation` only), so you can skip it, unless you have some logic to implement there.\n\n\u003e Note that the `wrappers` can be passed to any `cycleConnect`, even non-root, but `drivers` option is only valid for `root` Cycle and is ignored otherwise.\n\n```js\n// RootCycle.js\n\nimport { run } from '@cycle/run';\nimport { makeHTTPDriver } from '@cycle/http';\nimport onionify from 'cycle-onionify';\nimport { cycleConnect } from 'react-cycle-connect';\n\nconst drivers = { HTTP: makeHTTPDriver() };\nconst wrappers = [onionify];\n\nexport const RootCycle = cycleConnect({\n  root: true,\n  runFn: run,\n  drivers,\n  wrappers\n})();\n\nexport default RootCycle;\n```\n\n`RootCycle` component is basically in charge of bootstrapping the \"Cycle\" part of your app here.\n\nThen just wrap your `App` with it and e.g., render with `ReactDOM`:\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\nimport RootCycle from './RootCycle';\n\nReactDOM.render(\n  (\n    \u003cRootCycle\u003e\n      \u003cApp /\u003e\n    \u003c/RootCycle\u003e\n  ),\n  document.getElementById('root')\n);\n\n```\n\n\n### `render` option\n\nYou might have noticed in axamples above that we're not providing any component to a `cycleConnect` HOC, leaving empty braces instead:\n\n```js\nconst ConnectedComponent = cycleConnect({\n  root: true,\n  runFn: run,\n  drivers,\n  wrappers\n})();\n```\n\nWell, that is not a mistake - the wrapped component is optional. When a \"component to wrap\" is provided to `cycleConnect(...)(ComponentToWrap)`, then if we render the connected component, the `cycleConnect` will also render `ComponentToWrap` internally.\n \nThats all good and works (and what you'll be using most of the time anyway), but sometimes you just want to keep your React Element tree a bit cleaner when the wrapped component would be a kind of _noop_ anyway (just forwarding `children` and nothing else), or component is some technical/lower-level like `RootCycle`, or have some special rendering behavior.\n\nSo, we want to avoid seeing this in React Developer Tools:\n\n ```html\n  \u003ccycleConnect(SomeComponent)\u003e\n    \u003cSomeComponent\u003e\n      ...\n    \u003c/SomeComponent\u003e\n  \u003c/cycleConnect(SomeComponent)\u003e\n```\n\nYou can use `render` option for that. It accepts the function with this signature:\n```js\n(props) =\u003e ReactNode | null\n```\n\nIf no component is provided for wrapping, nor `render` option is defined, the `render` option defaults to `(props) =\u003e props.children || null` function, so its either forwarding `children` if any or renders nothing.\n\nIf both `render` option is provided and component-to-wrap is passed, then `render` takes the precedence.\n\n\u003e Note: Why not use the `render` option in place of wrapped component all the time? Well, its technically possible, espeically if your React component is a stateless functional component anyway.\n\u003e \n\u003e But regular HOC wrapping is just common technique in React world and is nicely composable when you have other HOCs than `cycleConnect`.\n\u003e\n\u003e And is cleaner too - you might be prototyping your app as a set of `React` components first, without even involving `react-cycle-connect`, then \"connect\" them all at once, or introduce `react-cycle-connect` incrementally. Whatever :)\n\n\n### `displayName` option\n\nYour component's `displayName` is by default automatically assigned to the following (depending on whether the wrapped component is provided, or `render` option, or neither:\n\n - `cycleConnect(WrappedComponentNameHere)` when WrappedComponent is passed\n - `cycleConnect(customRenderFn)` when `render` prop is defined (and is truthy)\n - `cycleConnect(defaultRenderFn)` otherwise\n\nYou can override that like with any regular React component:\n\n```js\nconst ConnectedComponent = cycleConnect({\n  ...\n)(Component);\n\nConnectedComponent.displayName = 'ConnectedComponent';\n```\n\nBut there's also a `displayName` option to set the generated (connected) component `displayName`, which looks a bit cleaner:\n\n```js\nconst ConnectedComponent = cycleConnect({\n  ...\n  displayName: 'ConnectedComponent'\n)(Component);\n```\n\n\n### Inside the Cycle\n\n`react-cycle-connect` really assumes that you know how to use Cycle.js. Its really a very simple yet very elegant pattern, so make sure to familiarize yourself with it.\n\nQuick recap on what Cycle.js `main` function is. Its basically a **pure** function with the signature:\n\n```js\nmain :: (Sources) =\u003e Sinks\n```\n\nIt accepts `sources` as an argument and returns `sinks` and describes a dataflow using composition of reactive streams and their transformations with pure functions.\n\n\u003e Please note that the `main` function **is only run once** per `React` component lifecycle. It doesn't run again on rerendering or something. This is because the actual call to `main(...)` is to just build up a **dataflow**, not to get some rendering data.\n\u003e\n\u003e The data flows through reactive streams, from `sources` to `sinks` of the `main`, until its `sinks` are unsubscribed from parent Cycle program's `sinkProxies` (this happens when React component is unmounted).\n\n\n#### Drivers\n\nThe `driver` is supposed to run side effects for a Cycle.js program. Its outside the program itself, supposed to be impure and connects your Cycle app with the \"outer world\". This is an essential concept and is described in a great detail in [Cycle.js docs on drivers](https://cycle.js.org/drivers.html).\n\nThere are no differences from idiomatic Cycle.js in how `react-cycle-connect` handles `drivers` - it just hands it over to `@cycle/run` directly. There is only one `react-cycle-connect` driver (an `fnCallEffect` driver) that is always added internally by the `cycleConnect({ root: true })`ed component - it allows to invoke functions outside the `main` that is to be maintained pure.\n\n\n#### Wrappers\n\nThe `wrapper` is a rather simple thing - its just a function that takes `main` function that wraps it with the other `main` function that might in turn add some logic in between:\n\n```js\nfunction someWrapper(originalMain) {\n  return wrappedMain(sources) {\n    // Can do something here, like transforming `sources` somehow\n    // ...\n\n    // Invoke the original `main` internally to obtain its sinks\n    const sinks = originalMain(sources);\n\n    // Can do something to `originalMain`s sinks here\n    // ...\n\n    return {\n      ...sinks,\n      someOtherSink: xs.of({ ... }) // Can add a new sink\n    };\n  }\n}\n```\n\nIt is important that the wrapping `main` is maintained **pure**, so that your entire program is pure. If you need some effectful logic to run in a wrapping `main`, you should consider using driver for that. Wrappers, just like any regular `main` function, can internally use `sources` that are created from `drivers`.\n\nWrappers can also add arbitrary `sources` and could expect certain `sinks` to be returned from the Cycle program, depending on particular wrapper implementation.\n\nWrappers are usually created to encapsulate some non-business-logic stuff, you'd be normally describe anything related to the app itself in the \"original\" `main` function.\n\nMost of `react-cycle-connect` (aside from `cycleConnect(...)` HOC itself) is implemented with wrappers, that are created for each `cycleConnect()`ed component automatically:\n- `reactPropsWrapper` (to mess around with React component props)\n- `reactLifecycleWrapper` (a gateway to React component lifecycle streams)\n- `interactionsWrapper` (to route the view events back from your wrapped React component aka **view**, and pass the events upstream, to parent components)\n\n\n#### Sources\n\nThis is a Cycle.js program's input. `main` function shouldn't care whether something on the `sources` is a `driver` or some custom thing provided by one of the wrappers.\n\nFor `root` connected component, the `sources` are `drivers` directly plus whatever `wrappers` add to them.\n\n\n#### Sinks\n\nThis is a Cycle.js program's output.\n\n`react-cycle-connect` invokes your `cycleConnect()`ed component's `main` function, takes its `sinks` and subscribes the `sinkProxies` passed from the parent component to these `sinks`. Its how `react-cycle-component` is \"attaching\" the new component to a tree of Cycle programs.\n\nIf there's no parent component (thus, no `sinkProxies`) and your component is a \"Root Cycle\", then the sinks are handled to `@cycle/run` to \"run\" as with a regular Cycle.js app.\n\n\n### React `props`\n\nThe `cycleConnect()`ed `React` component is essentially a **view** for the associated Cycle.js `main` function. And `react-cycle-connect` encourages the **view** to be a \"dumb\" stateless function that takes `props` as an argument ad returns something of `ReactNode` type (i.e., `ReactElement`s, `null`, etc, whatever `React` component renders).\n\n\u003e Note: The wrapped `React` shouldn't necessarily be a stateless functional component (SFC), you could have any `React` component wrapped, but its advisable to use functions for the most part as the whole point of `react-cycle-connect` is to use `Cycle.js` for anything that is not a **view**.\n\nSo, the `props` is the only communication channel from our Cycle.js part (the connected component's `main` function) to connected `React` component itself. We therefore need to pass the props from our Cycle program to the **view** (a `React` component) somehow.\n\nThis is where `reactPropsWrapper` comes into play and provides `props` source and sink for a `main` function. Its local to a component, so no other components will share the same `props` source or sink.\n\n#### `props` sink\n\nThe `props` _sink_ on `cycleConnect()`ed is there to pass the props to the view:\n\n```js\nfunction main(sources) {\n  return {\n    props: xs.of({ greetable: 'World' })\n  };\n}\n\n// Use the passed `greetable` prop\n\nfunction MyComponent(props) {\n  return (\n    \u003cdiv\u003e\n      Hello {props.greetable}!\n    \u003c/div\u003e\n  );\n}\n\nconst MyConnectedComponent = cycleConnect(main)(MyComponent);\n```\n\nRemember, that the value you map to `props` sink should be an object of new props and that updated props will be **merged** with existing component `props` like:\n```js\nconst updatedProps = Object.assign({}, prevProps, newProps);\n```\n\nThis means that you can easily overwrite any props you want and leave the others intact.\n\nAlso, note above that we're passing the `props` through an `Observable` stream and that might be synchronous (like in our example with a stream of static data that is sent immediately) but could also be asynchronous. In that case the value of some prop might be not yet available on the first render:\n\n```js\nfunction main(sources) {\n  return {\n    props: xs.of({ greetable: 'World' }).compose(delay(3000))\n  };\n}\n\n// Trying to use the passed `greetable` prop\n// But whooops, no `greetable` yet :(\n\nfunction MyComponent(props) {\n  return (\n    \u003cdiv\u003e\n      Hello {props.greetable}!\n    \u003c/div\u003e\n  );\n}\n\nconst MyConnectedComponent = cycleConnect(main)(MyComponent);\n```\n\nSo either provide a default value for that async prop's `Observable` or perform additional checks in the **view**, when rendering.\n\n\u003e Note: When messing with the `props` in your `main`, remember that any props that are passed from outside as an input to a `React` component, are also there (including **callback functions**, if there are any) and are also merged upon updates from outside (on `componentDidUpdate`).\n\nLets summarize: the `props` from the `props` sink are passed from the `main` function to the **view** (`React` component).\n\n#### `props` source\n\nNot only you'll need to provide the props to the **view** for rendering, but oftentimes you'd need your `props` to take part in transformations/calculations in the `main` function itself. For that reason, `reactPropsWrapper` provides the `props` source as well.\n\nIt allows you to have an `Observable` stream of your component's input `props`. Note that the `sources.props` is of type `ReactPropsSource` and to take the actual stream of props, use its `props$` attribute:\n\n```js\nfunction main(sources) {\n  const name$ = sources.props.props$.map(props =\u003e props.name);\n\n  return {\n    props: name$.map(name =\u003e ({ name: name.toUpperCase() }))\n  };\n}\n\nfunction MyComponent(props) {\n  return (\n    \u003cdiv\u003e\n      Hello, {props.name}! Your father is Mr. {props.father}.\n    \u003c/div\u003e\n  );\n}\n\nconst MyConnectedComponent = cycleConnect(main)(MyComponent);\n\n...\n\n// Somewhere else:\n\u003cMyConnectedComponent name=\"Luke Skywalker\" father=\"Darth Vader\" /\u003e\n\n// renders:\n//\n// \u003cdiv\u003e\n//   Hello, LUKE SKYWALKER! Your father is Mr. Darth Vader.\n// \u003c/div\u003e\n```\n\nThe new value on `props$` is emitted every time `props` change. This could be overkill for the most cases, as you would only need just few props for your dataflow.\n\nThis is what `ReactPropsSource.pluck()` method for, it accepts the name of the nested prop (will return `undefined` if the stream value is not an object) and returns a stream of that prop only that is only got new value once this particular prop changes:\n\n```js\nfunction main(sources) {\n  const name$ = sources.props.pluck('name');\n\n  return {\n    props: name$.map(name =\u003e ({ name: name.toUpperCase() }))\n  };\n}\n```\n\nThe `pluck()`ed stream also performs shallow comparison and does `dropRepeats()` behind the scenes, so identical values don't cause a new value emitted on an `Observable`.\n\nNote that you don't need to always pull all props from your `main` function's `sources.props` just for the sake of it to just forward to the `props` sink directly, you better only pick those you need in a dataflow with `ReactPropsSource.pluck()`. The `props` passed from outside will be available on the view normally. You can overwrite them from inside your `main` though.\n\nThere's also `ReactPropsSource.select()` method that also accepts a nested prop name. The difference is that the result is not an `Observable` stream of prop values but the `ReactPropsSource` instance itself that is _scoped_ to that piece of `props`:\n\n```js\nfunction main(sources) {\n  const name$ = sources.props.pluck('name'); // Stream of strings\n  const nameSource = sources.props.select('someNestedObject'); // Scoped ReactPropsSource\n\n  const someNestedObjProperty$ = nameSource.pluck('someNestedObjectProperty');\n  ...\n}\n\n```\n\nThis is useful when you want to `pluck()` a stream of some sub-prop from deeper nested objects.\n\n\u003e Note: Taking deep property stream this way isn't really nice currently as requires quite a bit of boilerplate - this part of API is already being thought out further and reconsidered.\n\n\n### Interactions\n\nSo far so good, but rendering the `props` isn't the only exciting thing we want to do with `React`, right? We also want to handle events coming from the **view**(e.g., the DOM).\n\nThe way `react-cycle-connect` handles events and nested components' callbacks is the biggest deviation from an idiomatic Cycle.js app using `DOM` driver. It refrains from a holistic \"no handlers in the view\" approach for a few reasons:\n\n- We need something more in line with `React` as we're using React here\n- We're not always handling DOM events but also need to handle some children components data/events passed back. We can't pass streams like in regular Cycle.js app, in `React` we do it via callbacks that are provided amongst children components' `props` and we need `cycleConnect()`ed components to be compatible `React` components at all levels.\n\nThis is what \"interactions\" feature of `react-cycle-connect` is for. It provides the unified interface for parent-child components communication and event handling that is aligned with a regular event/callback handling model on `React` side but also allows to access those events in form of `Observable` streams inside the `main` function.\n\n#### Events triggering by the view\n\nEvery `cycleConnect()ed` component has some additional `react-cycle-connect`-specific props injected, so they are available on your **view**.\n\nThese are `interactFn` which is a function that takes the `interactionType` (a string) and optional `predefinedValue` (of any type) and returns a function that will be a callback for your event or some child component prop function.\n\nSo, the signature is:\n```js\n(interactionType, predefinedValue?) =\u003e (value) =\u003e void\n```\n\nIts supposed to be called imperatively in your **view** and is available as `props.interact`:\n\n```js\nfunction MyComponent({ interact }) {\n  return (\n    \u003cdiv\u003e\n      \u003cbutton type=\"button\" onClick={interact('buttonClick')}\u003e\n        Click me!\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nFor the sake of being cleaner (and for better [TypeScript support](#typescript-support)), `react-cycle-connect` also leverages the ES2015 `Proxy` feature to provide the object with dynamic properties, each representing an `interact` with `interactionType` dynamically defined after the function property name. Its available on `props.interactions` so we can rewrite the above snippet as:\n\n```js\nfunction MyComponent({ interactions }) {\n  return (\n    \u003cdiv\u003e\n      \u003cbutton type=\"button\" onClick={interactions.buttonClick}\u003e\n        Click me!\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nIn the example above, the `interactions.buttonClick` function receives the click `event` as an argument and that is what you'll get in your `main` (next section).\n\nWhile cleaner, it doesn't allow for the `predefinedValue` to be set, so if you need some particular value to be emitted by the associated stream in your `main`, you can either use `interact` or create an inline function:\n\n```js\n// Assuming you have `id` available, e.g.\n// when looping/mapping over the collection of items\n\n\u003cbutton\n  type=\"button\"\n  className=\"delete-btn\"\n  onClick={interact('delete', id)}\n\u003e\n  Click me!\n\u003c/button\u003e\n\n// OR\n\n\u003cbutton\n  type=\"button\"\n  className=\"delete-btn\"\n  onClick={() =\u003e interactions.delete(id)}\n\u003e\n  Click me!\n\u003c/button\u003e\n```\n\n#### View events handling with `interactions` source\n\nThere's internal `interactionsWrapper` in `react-cycle-connect` and it provides the `interactions` source for our `main` function. The `interactions` source is of type `InteractionsSource`, which has the `InteractionsSource.select()` method, which we can use to obtain interaction streams:\n\n```js\nfunction main(sources) {\n  const buttonClick$ = sources.interactions.select('buttonClick');\n\n  // Do something with a buttonClick$, e.g.\n  // map it to the click coordinates props\n\n  return {\n    props: buttonClick$.map(\n      event =\u003e ({\n        clickX: event.clientX,\n        clickY: event.clientY,\n      })\n    )\n  };\n}\n\nfunction MyComponent({ interact, clickX, clickY }) {\n  return (\n    \u003cdiv\u003e\n      \u003cspan\u003e\n        Last clicked at: X - {clickX}, Y - {clickY}\n      \u003c/span\u003e\n\n      \u003cbutton type=\"button\" onClick={interact('buttonClick')}\u003e\n        Click me!\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst ConnectedComponent = cycleConnect(main)(MyComponent);\n```\n\nThe streams are `select()`ed by the same `interactionType` string you provided to the `interact()` function on your view.\n\nSimilar to how `interactions` object with dynamic function-props is available on your view, `InteractionsSource` is a ES2015 `Proxy` and it maintains the dynamic streams right on itself (just don't use `select` as its reserved method name here here):\n\n```js\nfunction main(sources) {\n  const buttonClick$ = sources.interactions.buttonClick;\n\n  return {\n    props: buttonClick$.map(\n      event =\u003e ({\n        clickX: event.clientX,\n        clickY: event.clientY,\n      })\n    )\n  };\n}\n\nfunction MyComponent({ interactions, clickX, clickY }) {\n  return (\n    \u003cdiv\u003e\n      \u003cspan\u003e\n        Last clicked at: X - {clickX}, Y - {clickY}\n      \u003c/span\u003e\n\n      \u003cbutton type=\"button\" onClick={interactions.buttonClick}\u003e\n        Click me!\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst ConnectedComponent = cycleConnect(main)(MyComponent);\n```\n\n\u003e Note: If you try to get the non-existing stream, it will still work, this thing is dynamic, so the stream will be created nevertheless but will just never emit values. Be careful and look out for typos! [Using TypeScript](#typescript-support) is highly recommended to avoid typos here.\n\n\n#### Upstream interactions with `interactions` sink (calling callbacks on `props`).\n\nNow that we can handle the streams of view events and values from the children components, we would also need to somehow call the callbacks that are passed among our `props`.\n\nFirst, nothing prevents from following the common React way and call those directly from the **view**:\n\n```js\nfunction MyComponent({ onButtonClick }) {\n  return (\n    \u003cbutton type=\"button\" onClick={onButtonClick}\u003e\n      Click me!\n    \u003c/button\u003e\n  );\n}\n\n// Somewhere else:\ndoSomething = (event) =\u003e { console.log('clicked!'); };\n\n...\n\n\u003cMyComponent onButtonClick={doSomething} /\u003e\n```\n\nThis is fine if you don't need that value's stream in your dataflow. This approach bypasses your Cycle.js program's `main` completely and doesn't make it impure by otherwise possibly passing an effectful function as `onButtonClick`. There's even no need to `cycleConnect()` your component in the above example.\n\nKeep in mind that if `onButtonClick` is optional there, you will also need to check whether that is defined before providing that as a callback (use `PropTypes` or TypeScript to mark it as either required or optional).\n\nOftentimes you will need to call some callback that lives on the `props` though, and this is what `interactions` sink provided by `interactionsWrapper` does:\n\n```js\nfunction main(sources) {\n  const buttonClick$ = sources.interactions.buttonClick;\n  const coords$ = buttonClick$.map(\n    event =\u003e ({\n      clickX: event.clientX,\n      clickY: event.clientY,\n    })\n  );\n\n  // We both update the `props` (to render it in this component)\n  // and pass upstream\n  return {\n    props: coords$,\n    interactions: xs.of({\n      onCoordsChange: coords$\n    })\n  };\n}\n\nfunction MyComponent({ interactions }) {\n  return (\n    \u003cdiv\u003e\n      \u003cspan\u003e\n        Last clicked at: X - {clickX}, Y - {clickY}\n      \u003c/span\u003e\n\n      \u003cbutton type=\"button\" onClick={interactions.buttonClick}\u003e\n        Click me!\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst ConnectedComponent = cycleConnect(main)(MyComponent);\n\n// Somewhere else:\nhandleCoordsChange = (coords) =\u003e {\n  console.log('New coordinates received: ', coords);\n};\n\n...\n\n\u003cConnectedComponent onCoordsChange={handleCoordsChange} /\u003e\n\n// The new coords will be rendered by the component\n// and the console will show the \"New coordinates received\"\n// with new coords too.\n```\n\nOnce the appropriate stream emits a value, that callback is called. It will also check if the callback was passed in the first place to skip the call attempt if no callback with a given name is passed among the `props`.\n\n**Important:** Note that `interactions` sink expects a stream of object whose property names correspond to callback names on `props` and property values are themselves streams too - whatever values those streams emit, will be passed as an argument to the callback.\n\nSo far so good, but we know that our `interactionsWrapper` is a **wrapper** and not a **driver**, so what if one passed the effectful function as a callback, e.g., `handleCoordsChange` passed as `onCoordsChange` above does a `console.log()` internally - that is a side effect, right?\n\nWell, this is why the function is not invoked directly, or inside the wrapper (since the wrapper is the part of the pure land of our `main`s), its using the `fnCallEffect` **driver** internally. More on this below in a section about [Side-effect control](#side-effect-control-and-fncalleffect-driver), just keep in mind that `wrappers` and `main` should be pure and `react-cycle-connect` follows that requirement.\n\n\n### React component lifecycle streams\n\nYou're probably not going to need `React` component lifecycle hooks often inside your `main`, but still - they are provided via special `reactLifecycleWrapper`. It provides the `lifecycle` **source** that is available on each `cycleConnect()`ed `main` sources.\n\nThe lifecycle events are provided as `Observable` streams and their names mostly mirror the React [lifecycle methods](https://reactjs.org/docs/react-component.html#the-component-lifecycle), but shortened to remove some redundant `component` prefixes:\n\n| React lifecycle method      | `lifecycle` source property | Stream value     |\n|-----------------------------|-----------------------------|------------------|\n| `componentWillMount`        | `willMount$`                | `null`           |\n| `componentDidMount`         | `didMount$`                 | `null`           |\n| `componentWillReceiveProps` | `willReceiveProps$`         | `nextProps`      |\n| `componentWillUpdate`       | `willUpdate$`               | `nextProps`      |\n| `componentDidUpdate`        | `didUpdate$`                | `prevProps`      |\n| `componentWillUnmount`      | `willUnmount$`              | `null`           |\n| `componentDidCatch`         | `didCatch$`                 | Error data       |\n\nThe \"error data\" on the `didCatch$` is an object of this shape:\n```js\n{\n  error: Error;\n  errorInfo: ErrorInfo;\n}\n```\nThese are basically React `componentDidCatch(error, errorInfo)` arguments squashed into a single object.\n\nAlso, note that `shouldComponentUpdate` hook is not present there, since that is not really an **event** and affects how your component is rendered. `react-cycle-connect` would be providing its own custom internal `shouldComponentUpdate` instead for optimisation purposes and you could implement it on your wrapped component anyway.\n\n\u003e Note: As well, no lifecycle events are passing anything related to React component `state`, only taking `props` into account instead. This is because the `state` is meant to be managed differently when Cycle.js is in use. You can still use that for wrapped component but its out of play on the component generated by `cycleConnect(...)`.\n\nA quick example:\n\n```js\nfunction main(sources) {\n  const willUnmount$ = { sources.lifecycle };\n\n  // Do something on unmounting, e.g. report that to a console\n  // via some hypothetical `logger` driver\n  return {\n    logger: willUnmount$.mapTo(`I'll be unmounted soon!`)\n  };\n}\n```\n\n\n### Side-effect control and `fnCallEffect` driver\n\nSide-effect control is where Cycle.js really shines (not only implementation, it applies to the \"cycle pattern\" behind Cycle.js in the first place).\n\nIn order to keep the `cycle` part of `cycleConnect()`ed component pure, we need to make sure that any potentially effectful function is not run inside our `main` directly.\n\nThis is what `fnCallEffect` driver is responsible for. It allows to only **describe** what function you want to call and with what arguments, then delegate that to a `driver` which is supposed to run any impure functions outside of the app itself.\n\nThe way it works is very similar to that of `HTTP` driver from `@cycle/http` package where you don't actually run the request inside your `main` but just describe it and pass to `HTTP` driver to handle. `fnCallEffect` driver is just a bit more generic and operates on functions.\n\n`react-cycle-connect` uses `fnCallEfffect` driver internally (to run effects for upstream `interactions`), but it is also available for you on any connected `main` as `fnCallEffect` **sink** automatically (i.e., without explicit configuration on a **root** cycle):\n\n```js\nfunction log() {\n  console.log(`I'm effectful!`);\n}\n\nfunction saveToLocalStorage(message) {\n  localStorage.setItem('message', message);\n}\n\nfunction main(sources) {\n  const someCallbackFn$ = sources.props.pluck('someCallbackFunction');\n\n  return {\n    fnCallEffect: xs.merge(\n      xs.of({ fn: log }),\n      xs.of({ fn: saveToLocalStorage, args: ['some message to save'] }),\n      // Call the `props` callback function directly, this is how\n      // `interactions` sink works behind the scenes:\n      someCallbackFn$.map(fn =\u003e ({ fn }))\n    )\n  };\n}\n```\n\n\n### Isolation\n\n**Isolation** is Cycle.js way of making the component's `sources` and `sinks` isolated from influence of other components.\n\nMake sure to carefully read more about Cycle.js isolation [here](https://cycle.js.org/api/isolate.html). It might take a bit to get used to an idea.\n\nTo reiterate: the concept of **isolation** is important for Cycle.js apps. Its a little bit different for `react-cycle-connect` because most things are scoped to a particular `cycleConnect()`ed component already, like components have \"local\" `interactions`, `props` and `lifecycle` sources and sinks and `React` components are also self-contained already.\n\nThere are though `drivers`/`wrappers` that will need the **isolation** feature, like `HTTP` driver or `cycle-onionify` wrapper (a state management solution for Cycle.js apps). So, **isolation** makes sense for shared `drivers`/`wrappers`, those you pass to `@cycle/run` function (by defining the `drivers`/`wrappers` options on **root** `cycleConnect(...)`) and that will be available across the entire tree of Cycle programs.\n\n\u003e Note: The isolation works by **scoping** the source streams to particular component and a kind of **unscoping** of the sink streams before connecting to parent's sinks.\n\u003e\n\u003e Also note, that each driver/wrapper decides on its own how its sources/sinks should be isolated.\n\nIn Cycle.js, you use the `isolate()` function from [`@cycle/isolate`](https://www.npmjs.com/package/@cycle/isolate) package directly, as you're just invoking the children `main` functions from your current component's `main` function:\n\n```js\nfunction main(sources) {\n  const childSinks = isolate(childMain, { DOM: 'foo', HTTP: 'bar' })(sources);\n\n  // Do something with childSinks, combine somehow, etc\n\n  return {\n    ...\n  };\n}\n```\n\n`isolate` function has this simple signature:\n```js\nisolate :: (MainFn, scope) =\u003e MainFn\n```\n\nIt takes the `main` function and an optional `scope` and returns an isolated `main` function.\n\n`react-cycle-connect` does also use the `@cycle/isolate` package internally, but you can't call `isolate()` directly on some `childMain` function. You'd never call one component's `main` from the other component's `main` directly with `react-cycle-connect`.\n\n#### Naive explicit isolation (conceptually incorrect)\n\nJust to illustrate the issue, there's an attempt to isolate the component's `HTTP` sources, so that HTTP requests initiated from that components are scoped to it (and are unavailable to siblings).\n\nSince we know that `isolate()` returns a `main` function and `cycleConnect()` takes the `main` function as an argument, lets try to feed it an isolated version of it:\n\n```js\nfunction main(sources) {\n  ...\n}\n\nfunction MyComponent() {\n  ...\n}\n\nconst isolatedMain = isolate(main, { HTTP: 'myComponent' });\nconst ConnectedComponent = cycleConnect(isolatedMain)(MyComponent);\n```\n\nWhile this will won't raise any errors (because this is valid code after all), this approach brings a subtle issue.\n\nThis will isolate things for this particular components but **not their children components**, so in this case, children (connected childred `React` components) will have no `myComponent` isolation scope for `HTTP` channel.\n\nThis might seems like a no-issue, because hey, you can define different scopes for the children components right? Well, while this is technically possible, its conceptually incorrect and it will be completely broken in some cases, e.g., with `cycle-onionify` where  the deeper you go - the \"more filtered\" source streams you get.\n\n**Important!** The above note about it being \"conceptually incorrect\" refers to the way `react-cycle-connect` maintains the tree of Cycle.js programs internally. It tries to make the entire app structure **look** the same way as you'd manually write a Cycle.js app. So, when you `isolate(childMain)` at some level, then if inside your `childMain` you also call some `grandChildMain(...)` happens, then `grandChildMain` gets isolated sources no matter what.\n\n\n#### `isolate` option for `cycleConnect()`\n\nThe first way to correctly isolate `cycleConnect()`ed component is to use the `isolate` option for `cycleConnect()` itself, so the above can be rewritten as:\n\n```js\nfunction main(sources) {\n  ...\n}\n\nfunction MyComponent() {\n  ...\n}\n\nconst ConnectedComponent = cycleConnect(main, {\n  isolate: { HTTP: 'myComponent' }\n})(MyComponent);\n```\n\nThis will work perfectly, with all children `cycleConnect()`ed components having `myComponent` namespace applied to `HTTP` sources/sinks in their `main` functions.\n\nThe `isolate` option accepts a `string` or the `object` and in that case its passed directly to `@cycle/isolate` package's `isolate(main, scope)` as a `scope` argument. So, check out the [`isolate` function API reference](https://cycle.js.org/api/isolate.html.).\n\n`react-cycle-connect` also makes it accept a function that takes component `props` as an argument and should return the scope of `string` or `object` type that is then also passed to `@cycle/isolate` package's `isolate(main, scope)`. This allows for some dynamic isolation scopes to be set based on the React component's initial props.\n\n\u003e **Important**: Despite the `isolate` is provided as an option to `cycleConnect()` when defining the connected component, the actual isolation will only happen when **component instance** is created. This is why its possible to dynamically resolve the `scope` based on the component `props` in `react-cycle-connect`.\n\n\n#### `isolate` prop\n\nDespite the `isolate` option will work nicely for some cases, there's a pattern in how it is utilized in pure Cycle.js programs. Lets take a look at pure Cycle.js example again:\n\n```js\nfunction main(sources) {\n  const childSinks = isolate(childMain, { DOM: 'foo', HTTP: 'bar' })(sources);\n\n  // ...\n\n  return {\n    ...\n  };\n}\n```\n\nThe important part is that in Cycle.js app its not a child who decides how to isolate itself but `scope` is provided from the parent instead.\n\nMost of the time, we want to maintain the same approach with `react-cycle-connect`. The advantage is that component in this case is totally agnostic from the provided scope, it doesn't even care whether its isolated or not at all - all it knows is that it expects certain `sources` and returns certain `sinks`. This makes the component reusable.\n\nThis is especially important with `cycle-onionify`, where you want to control where your child components \"attach\" to the state.\n\nIn other words, the parent decides how to compose children components, not the other way around, because otherwise the child would need to have an intimate knowledge of something that really belongs to parent and thus not being reusable and breaking encapsulation.\n\nFor this reason, every `cycleConnect`ed React component accepts an `isolate` prop, so you can use that just like any other prop:\n\n```js\nfunction main(sources) {\n  ...\n}\n\nfunction MyComponent() {\n  ...\n}\n\nconst ConnectedComponent = cycleConnect(main)(MyComponent);\n\n// Somewhere else:\n\n// Isolate everything\n\u003cConnectedComponent isolate=\"myComponent\" /\u003e\n\n// Isolate HTTP only\n\u003cConnectedComponent isolate={{ HTTP: 'myComponent' }} /\u003e\n\u003cConnectedComponent isolate={{ HTTP: 'myComponent_2' }} /\u003e\n```\n\nIn contrast with [`isolate` option](#isolate-option), the `isolate` prop can only accept `string` or `object` that is directly passed to `isolate()` function from `@cycle/isolate`, thus maintaining full parity with pure Cycle.js approach. Indeed, having a function that accepts initial `props` wouldn't make much sense because you're anyway providing props that could be different for different component instances when rendering that component.\n\n\n#### `\u003cIsolator\u003e` helper component\n\nSince isolation in `react-cycle-connect` applies to both \"current\" `cycleConnect()`ed component and all its `cycleConnect()`ed children, we might sometimes need to define some connected component to only be a common parent for some children, which must provide isolation but wouldn't contain any logic.\n\nThis is what a helper `Isolator` component for. It accepts the `scope` prop (that is directly passed as a `scope` argument to `isolate(main, scope)` function of `@cycle/isolate`):\n\n```js\n\u003cIsolator scope={{ HTTP: 'someNamespace' }}\u003e\n  \u003cConnectedComponent someProps=\"1\" /\u003e\n  \u003cConnectedComponent someProps=\"2\" /\u003e\n  \u003cConnectedComponent someProps=\"3\" /\u003e\n\u003c/Isolator\u003e\n```\n\nThis assists the isolation composition at view level.\n\n\n### Extra: State management with `cycle-onionify`\n\n[`cycle-onionify`](https://github.com/staltz/cycle-onionify) is the idiomatic Cycle.js fractal state management solution. It is tailored for Cycle.js apps but since `react-cycle-connect` is using the real Cycle.js, it stays fully compatible here as well.\n\nUsing `cycle-onionify` with `react-cycle-connect` is optional, since you might be using different lib (e.g., `redux`) for that. \n\nTo start, just read the [onionify docs](https://github.com/staltz/cycle-onionify) and install the package:\n\n```\n$ npm install --save cycle-onionify\n```\n\nand pass that with `wrappers` array to a `root` connected component (e.g., [Root Cycle](#root-cycle)):\n\n```js\n// RootCycle.js\n\nimport { run } from '@cycle/run';\nimport onionify from 'cycle-onionify';\nimport { cycleConnect } from 'react-cycle-connect';\n\nconst wrappers = [onionify];\n\nexport const RootCycle = cycleConnect({\n  root: true,\n  runFn: run,\n  wrappers\n})();\n\nexport default RootCycle;\n```\n\nNow every `cycleConnect()`ed component that is a child of the above-mentioned `RootCycle` in React component tree got the `onion` source and sink.\n\n**Important:** Notice that **you're all set** - its purely a Cycle.js land. `react-cycle-connect` **doesn't** provide any additional functionality for `cycle-onionify`. Instead, it provides few helpers for isolation and working with collections on the React side.\n\nAll the exportables related to `onionify` reside in the extra package: `react-cycle-connect/lib/extra/onionify`. It is installed along with the main lib but is not `require()`d/`import`ed by default, so won't be bundled (by Webpack, Rollup, etc) unless you're using it.\n\nThis extra sub-package contains few things:\n\n- `\u003cStateIsolator\u003e` helper component\n- `\u003cCollection\u003e` helper component\n- `makeFilteredListLens()` helper factory function\n\nRead ahead for details on each.\n\nIn `cycle-onionify`, the state/reducers layer composition is done via [isolation](#isolation), so the first thing here is `\u003cStateIsolator\u003e`:\n\n\n#### `\u003cStateIsolator\u003e` helper component\n\nThis is pretty much like [`\u003cIsolator\u003e`](#isolator-helper-component) but is here to specifically isolate `onion` sources/sinks only.\n\nSo, the:\n\n```js\nimport { StateIsolator } from 'react-cycle-connect/lib/extra/onionify';\n\n// ...\n\n\u003cStateIsolator lens=\"someStateProperty\"\u003e\n  \u003cNestedComponent /\u003e\n\u003c/StateIsolator\u003e\n```\n\nis somewhat a convenient shortcut to:\n\n```js\nimport { Isolator } from 'react-cycle-connect';\n\n// ...\n\n\u003cIsolator scope={{ onion: 'someStateProperty', '*': null }}\u003e\n  \u003cNestedComponent /\u003e\n\u003c/Isolator\u003e\n```\n\nNotice how `StateIsolator`'s prop is explicitly named `lens`. It just implies that oftentimes you'll be using [\"lens\"](https://github.com/staltz/cycle-onionify#how-to-share-data-among-components-or-compute-derived-data) to isolate the state. Consider a string just a shortcut to a more elaborate `lens` object.\n\nIn the example above, the `\u003cNestedComponent\u003e`'s `main` function `sources.onion.state$` will represent only that \"someStateProperty\" piece of state. Pretty much how you'd `isolate()` the `onion` channel in an idiomatic Cycle.js app.\n\nThere's also a `channelName` property, so that you can change the name of the source/sink inside your `main` to something else. Thats to be on par with `cycle-onionify` features, where you can also change that name.\n\n\n#### Handling collection state manually\n\nManaging collections of components in pure Cycle.js with `onionify` is a kind of a recognized challenge. This is why `cycle-onionify` ended up providing `makeCollection()` helper function - [see their docs](https://github.com/staltz/cycle-onionify#how-to-handle-a-dynamic-list-of-nested-components) for more detail.\n\nWhile `react-cycle-connect` also has a `\u003cCollection\u003e` helper component that is very similar to `cycle-onionify` `makeCollection()` function, lets first try to pretend we don't have it and imagine how'd we handle the state without it.\n\n\u003e **Note:** Nothing prevents you from skipping right to [a description of how `\u003cCollection\u003e` works](#collection-helper-component), but it might be useful to understand the rationale behind it, so reading this section is recommended.\n\nHandling collections is different with React than in Cycle.js, e.g., you can always just render React components in a loop or `.map()` an array of data to an array of components and React will render that.\n\nWhen you want to render some `Array` data from your **state**, its easy without any helpers:\n\n```js\n/*\n  Assume you have this value on your `List` component `state$`:\n\n  {\n    list: [\n      { id: 1, name: 'Obi-Wan Kenobi', kills: 100 },\n      { id: 2, name: 'Luke Skywalker', kills: 25 },\n      { id: 3, name: 'Darth Vader', kills: 9000 }\n    ]\n  }\n*/\n\n// ListItem.jsx\n\nfunction ListItem({ itemData }) {\n  return (\n    \u003cli\u003e\n      {itemData.name} (ID: {itemData.id}, kills: {itemData.kills})\n    \u003c/li\u003e\n  );\n}\n\n// List.jsx\n\nfunction main(sources) {\n  // Just pass as `props` directly\n  return {\n    props: sources.onion.state$\n  };\n}\n\nfunction List({ list }) {\n  return (\n    \u003cul\u003e\n      {list.map(item =\u003e (\n        \u003cListItem key={item.id} itemData={item} /\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n}\n\nconst ConnectedList = cycleConnect(main)(List);\n```\n\nThis keeps your `ListItem` component just a \"dumb\" view, there's no even need of connecting it to the Cycle tree. So far so good.\n\nThen you want to add more item-level capabilities, like editing an item (incrementing hero `kills` in our case, for simplicity) or deleting an item. You can still manage the state in the `List` component, act upon some callbacks for particular item and only stream reducers from inside `List` component's `main`:\n\n```js\n/*\n  Assume you have this value on your `List` component `state$`:\n\n  {\n    list: [\n      { id: 1, name: 'Obi-Wan Kenobi', kills: 100 },\n      { id: 2, name: 'Luke Skywalker', kills: 25 },\n      { id: 3, name: 'Darth Vader', kills: 9000 }\n    ]\n  }\n*/\n\n// ListItem.jsx\n\nfunction ListItem({ itemData, onIncrementClick, onDeleteClick }) {\n  return (\n    \u003cli\u003e\n      {itemData.name} (ID: {itemData.id}, kills: {itemData.kills}) -\n      \u003cbutton type=\"button\" onClick={onIncrementClick}\u003e\n        Increment \"kills\"\n      \u003c/button\u003e\n\n      \u003cbutton type=\"button\" onClick={onDeleteClick}\u003e\n        Delete\n      \u003c/button\u003e\n    \u003c/li\u003e\n  );\n}\n\n// List.jsx\n\nfunction intent(interactions) {\n  return {\n    itemIncrement$: interactions.itemIncrementClick,\n    itemDelete$: interactions.itemDeleteClick\n  };\n}\n\nfunction model(actions) {\n  const defaultReducer$ = xs.of(function defaultReducer(state) {\n    if (typeof state !== 'undefined') return state;\n    return {\n      list: []\n    };\n  });\n\n  const incrementItemReducer$ = actions.itemIncrement$.map(\n    (id) =\u003e function incrementItemReducer(state) {\n      return {\n        ...state,\n        list: state.list.map(listItem =\u003e {\n          if (listItem.id !== id) return listItem;\n          return {\n            ...listItem,\n            kills: listItem.kills + 1\n          };\n        })\n      };\n    }\n  );\n\n  const deleteItemReducer$ = actions.itemDelete$.map(\n    (id) =\u003e function deleteItemReducer(state) {\n      return {\n        ...state,\n        list: state.list.filter(listItem =\u003e listItem.id !== id)\n      };\n    }\n  );\n\n  return xs.merge(\n    defaultReducer$,\n    incrementItemReducer$,\n    deleteItemReducer$\n  );\n}\n\nfunction main(sources) {\n  const actions = intent(sources.interactions);\n  const reducer$ = model(actions);\n\n  return {\n    onion: reducer$,\n    props: sources.onion.state$\n  };\n}\n\nfunction List({ interactions, list }) {\n  return (\n    \u003cul\u003e\n      {list.map(item =\u003e (\n        \u003cListItem\n          key={item.id}\n          itemData={item}\n          onIncrementClick={() =\u003e interactions.itemIncrementClick(item.id)}\n          onDeleteClick={() =\u003e interactions.itemDeleteClick(item.id)}\n        /\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n}\n\nconst ConnectedList = cycleConnect(main)(List);\n```\n\nThere is already some noise in reducers, especially on updates. Also, what if there's another piece of state sibling to `list` property? `List` gets overburdened quickly.\n\nYou'd also quickly realize that this makes the collection item state inherently bound to `List`, so while you could be reusing `ListItem` somewhere else, you couldn't reuse its state management part.\n\nThis is unfortunate because certain actions (\"edit\" and \"delete\") are related to a single item and can be managed at that item's level. This is totally possible with `cycle-onionify` because its a **fractal state** management thing, so we could be taking advantage of that **fractal** aspect with `react-cycle-connect` too.\n\nSo, we'd better be managing internal item state at the `ListItem` component level. To do that, let's `cycleConnect` the `ListItem` component and make it handle its stuff. We need to carefully let each item's component know which piece of state does belong to it, and we'll use `listLens` for that:\n\n```js\n/*\n  Assume you have this value on your `List` component `state$`:\n\n  {\n    list: [\n      { id: 1, name: 'Obi-Wan Kenobi', kills: 100 },\n      { id: 2, name: 'Luke Skywalker', kills: 25 },\n      { id: 3, name: 'Darth Vader', kills: 9000 }\n    ]\n  }\n*/\n\n// ListItem.jsx\n\nfunction intent(interactions) {\n  return {\n    increment$: interactions.incrementClick,\n    delete$: interactions.deleteClick\n  };\n}\n\nfunction model(actions) {\n  // Note: default reducer assumes that we always have a valid\n  // state from the parent component. It just makes it undefined\n  // explicitly otherwise.\n  const defaultReducer$ = xs.of(function defaultReducer(state) {\n    if (state) return state;\n    return void 0;\n  });\n\n  const incrementReducer$ = actions.increment$.map(\n    () =\u003e function incrementReducer(state) {\n      return {\n        ...state,\n        kills: state.kills + 1\n      };\n    }\n  );\n\n  const deleteReducer$ = actions.delete$.map(\n    () =\u003e function deleteReducer(state) {\n      return void 0;\n    }\n  );\n\n  return xs.merge(\n    defaultReducer$,\n    incrementReducer$,\n    deleteReducer$\n  );\n}\n\nfunction main(sources) {\n  const actions = intent(sources.interactions);\n  const reducer$ = model(actions);\n\n  /*\n  The initial `state$` value is something like this,\n  due to isolation on the `List`.\n\n    {\n      id: 1,\n      name: 'Obi-Wan Kenobi',\n      kills: 100\n    }\n\n  */\n\n  return {\n    onion: reducer$,\n    props: sources.onion.state$.map(state =\u003e ({ itemData: state }))\n  };\n}\n\nfunction ListItem({ interactions, itemData }) {\n  return (\n    \u003cli\u003e\n      {itemData.name} (ID: {itemData.id}, kills: {itemData.kills}) -\n      \u003cbutton type=\"button\" onClick={interactions.incrementClick}\u003e\n        Increment \"kills\"\n      \u003c/button\u003e\n\n      \u003cbutton type=\"button\" onClick={interactions.deleteClick}\u003e\n        Delete\n      \u003c/button\u003e\n    \u003c/li\u003e\n  );\n}\n\nconst ConnectedListItem = cycleConnect(main)(ListItem);\n\n\n// List.jsx\n\nfunction model() {\n  const defaultReducer$ = xs.of(function defaultReducer(state) {\n    if (typeof state !== 'undefined') return state;\n    return {\n      list: []\n    };\n  });\n\n  // const addItemReducer$ = ...\n\n  return xs.merge(\n    defaultReducer$,\n    // addItemReducer$, etc\n  );\n}\n\nfunction main(sources) {\n  const reducer$ = model();\n\n  return {\n    onion: reducer$,\n    props: sources.onion.state$ // Merge state into props\n  };\n}\n\n// A lens for particular item, to extract/update its state correctly\nfunction itemLens(id) {\n  return {\n    get(arr) {\n      if (typeof arr === 'undefined') return void 0;\n      for (let i = 0, n = arr.length; i \u003c n; ++i) {\n        if (arr[i].id === id) {\n          return arr[i];\n        }\n      }\n      return void 0;\n    },\n\n    set(arr, updatedItemState) {\n      if (typeof arr === 'undefined') {\n        return [item];\n      } else if (typeof item === 'undefined') {\n        return arr.filter((itemState) =\u003e itemState.id !== id);\n      }\n\n      return arr.map((itemState) =\u003e {\n        if (itemState.id === id) return updatedItemState;\n        return itemState;\n      });\n    }\n  };\n}\n\n// Note that we no longer need to pass the data to list items,\n// they get it from `onion` state directly, on their own, but we still\n// need to provide the instructions on how to `isolate` each item state,\n// so that each component knows what item from collection it renders.\nfunction List({ interactions, list }) {\n  return (\n    \u003cul\u003e\n      {list.map(item =\u003e (\n        \u003cConnectedListItem\n          key={item.id}\n          isolate={{ onion: itemLens(item.id) }}\n        /\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n}\n\nconst ConnectedList = cycleConnect(main)(List);\n```\n\nThere's another issue with this. Now our `listLens` is intrinsically bound to a `list` property on a component state and , because we _just know_ that the `ConnectedList` component state is of the shape:\n\n```js\n{\n  list: []\n}\n```\n\nand item state has an `id` attribute. But what if `List` state is:\n\n```js\n{\n  someOtherListProp: []\n}\n```\n\nor something else, or has other properties along the way, which we'd need to take into account then:\n\n```js\n{\n  someOtherListProp: [],\n  somethingElse: 'some string',\n  someOtherProp: 123,\n  someNestedObject: { ... }\n}\n```\n\nor (unlikely but still possible), the actual collection is an item in some other collection:\n```js\n{\n  [\n    [], // list 1\n    [], // list 2\n    [], // list 3\n    [] // etc\n  ]\n}\n```\n\nAlso, what if there's another `key` for collection item and not an `id` attribute`?\n\nTo make item lens reusable, we need it to assume that the collection state is always an `Array` (or `undefined`) and pass a function to calculate the `key`. \n\nLets refactor this a bit, by extracting the use-case-specific property names out and explicitly isolate our list rendering with `\u003cStateIsolator\u003e` (unrelated code is omitted):\n\n```js\n// ...\n\n// A lens for particular item, to extract/update its state correctly\n// Note that we replaced the `id` with the more generic `key` and\n// the function now accepts another function as an argument, that\n// obtains the \"key\" to compare.\nfunction itemLens(key, itemKeyFn) {\n  return {\n    get(arr) {\n      if (typeof arr === 'undefined') return void 0;\n      for (let i = 0, n = arr.length; i \u003c n; ++i) {\n        if (itemKeyFn(arr[i], i) === key) {\n          return arr[i];\n        }\n      }\n      return void 0;\n    },\n\n    set(arr, updatedItemState) {\n      if (typeof arr === 'undefined') {\n        return [item];\n      } else if (typeof item === 'undefined') {\n        return arr.filter(\n          (itemState, index) =\u003e itemKeyFn(itemState, index) !== key\n        );\n      }\n\n      return arr.map((itemState, index) =\u003e {\n        if (itemKeyFn(itemState, index) === key) {\n          return updatedItemState;\n        } else {\n          return itemState;\n        }\n      });\n    }\n  };\n}\n\nfunction List({ interactions, list }) {\n  return (\n    \u003cul\u003e\n      \u003cStateIsolator lens=\"list\"\u003e\n        {list.map(item =\u003e (\n          \u003cConnectedListItem\n            key={item.id}\n            isolate={{ onion: itemLens(item.id, (item, index) =\u003e item.id) }}\n          /\u003e\n        ))}\n      \u003c/StateIsolator\u003e\n    \u003c/ul\u003e\n  );\n}\n\nconst ConnectedList = cycleConnect(main)(List);\n```\n\n\nAlright, this works but wow, there's a lot of boilerplate to write overall for this kind of thing every time, isn't there? We might also be reusing the `listLens` as its generic enough, so why not have it extracted to a package? Well, thats why we have a `\u003cCollection\u003e` component that encapsulates the repetitive boilerplate.\n\n\n#### `\u003cCollection\u003e` helper component\n\nThis helper component somewhat mirrors the functionality of `makeCollection()` helper function from `cycle-onionify`. It allows to avoid the repetitive boilerplate from collection to collection. `\u003cCollection\u003e` is itself just a `cycleConnect()`ed component.\n\nIt provides two levels of `onion` source/sink isolation internally - one for \"collection\" piece of state and then for each rendered item. The collection state isolation is required in order for it to be truly reusable (i.e., we can't just hardcode the `\u003cCollection\u003e` state to always be some `list` prop - instead, its made a userland decision, see previous section for a more elaborate description). So, `\u003cCollection\u003e` state is always expected to be an `Array` (or `undefined`).\n\nCollection isolation is configured with a `lens` prop (read more about lens in [`cycle-onionify` docs](https://github.com/staltz/cycle-onionify#how-to-share-data-among-components-or-compute-derived-data)):\n\n```js\nconst fooLens = {\n  get: (state) =\u003e state.foo,\n  set: (state, childState) =\u003e ({ ...state, foo: childState })\n};\n\n\u003cCollection lens={fooLens} ... /\u003e\n```\n\nFor such a straightforward use case (its very common) the `string` shortcut of the above will suffice:\n\n```js\n\u003cCollection lens=\"foo\" ... /\u003e\n```\n\nEach item's isolation is implemented internally (with `itemLens`) and is the core feature of `\u003cCollection\u003e`.\n\n\u003e Note: The code for `itemLens` is almost entirely burrowed from the `cycle-onionify` codebase - could even probably be reused as is if `cycle-onionify` package `export`s that.\n\nYou need to specify what component you want rendered as a collection item with `itemComponent` prop:\n\n```js\n\u003cCollection lens=\"foo\" itemComponent={ListItem} /\u003e\n```\n\nNote that `\u003cCollection\u003e` provides isolation for each item and `cycleConnect()`ed list item is supposed to just pull its data from `sources.onion.state$` directly. By default, though, `\u003cCollection\u003e` also passes the (already correctly isolated) item state as item component's `props` for convenience and for it to work with non-`cycleConnect()`ed item components.\n\n\u003e Note: Due to architecture of `react-cycle-connect`, there are no alternatives to `collectSinks` option and `pickMerge` and `pickCombine` helpers from `cycle-onionify`, because sink streams are handled differently in `react-cycle-connect` and they always behave as being `pickMerge()`d here.\n\n**Additional options**.\n\nWe know that React, when rendering a collection, requires a `key` prop to be defined on an item component. `\u003cCollection\u003e` does that for you internally and uses the item's `index` (position in a list) for that by default. In order to customize the `key` (used for both React and internal `itemLens`), you can pass an `itemKeyFn` prop that accepts a function of this signature:\n\n```js\n(itemState, index?) =\u003e Key;\n```\n\nMust return a React-compatible `Key` value. Quick example on how to set that to use item's `id` attribute:\n\n```js\n\u003cCollection\n  lens=\"foo\"\n  itemComponent={ListItem}\n  itemKeyFn={(itemState) =\u003e itemState.id}\n/\u003e\n```\n\n`\u003cCollection\u003e`, with the internal use of `listLens`, provides **only** `onion` source/sink isolation for each item by default. If you need other channels to be isolated somehow, you can provide `itemIsolate` property, which will be just passed as every item's `isolate` prop. Notr, though, that explicitly setting `onion` channel scope will be ignored - `\u003cCollection\u003e` will overwrite that internally.\n\nNext option is `channelName` which, just like with `\u003cStateIsolator\u003e` is supposed to change the `onion` to something else (like `stateTree` maybe).\n\nLastly, if you want to tweak the way your item component is rendered, you can pass the `itemRender` prop to the collection, which needs to be a function compatible with the signature:\n\n```js\n(itemState, itemKey, index) =\u003e ReactNode\n```\n\nPlease note that it completely overrides the item rendering and in this case you're on your own - the `itemComponent` and `itemIsolate` props will be ignored, as well as no `itemLens` will be applied to the item component internally and you'll need to provide the `key` on your own. This is just an escape hatch and is not supposed to be used often (or probably ever):\n\n```js\n\u003cCollection\n  lens=\"list\"\n  itemRender={(itemState) =\u003e (\n    \u003cListItem\n      {...itemState}\n      key={itemState.id}\n      isolate={{ onion: someCustomItemLens(itemState.id) }}\n    /\u003e\n  )}\n/\u003e\n```\n\n\n#### `makeFilteredListLens()` factory function to assist `\u003cCollection\u003e`\n\nAlrighty. One more important aspect of `lens` is that they're useful and are suggested approach for [computed `props` and derived data](https://github.com/staltz/cycle-onionify#how-to-share-data-among-components-or-compute-derived-data).\n\nSo, the `lens` prop on `\u003cCollection\u003e` isn't always supposed to be a shortbut prop name as oftentimes you'd want to show a filtered version of your collection. Since the only responsibility of `\u003cCollection\u003e` is to just isolate state nicely and render items, filtering the collection data is a userland option.\n\nThere are no special props on `\u003cCollection\u003e` to filter data but since it accepts `lens`, we can leverage that and provide a `lens` object that will \"zoom\" to a filtered subset of our collection data on `get` and merge things back on `set`.\n\nYou can write that `filteredListLens` manually, but the use case is so common that there's a helper included into the package. Lets see an example (from our [TodoMVC](https://github.com/VasilioRuzanni/react-cycle-connect/tree/master/examples/todomvc)) with \"todo\" items that also reads a value from state to decide, based on the `filter` value, which function to use in the predicate:\n\n```js\nimport { makeFilteredListLens } from 'react-cycle-connect/lib/extra/onionify';\n\nconst TODO_FILTER_FUNCTIONS = {\n  ['show_all']: () =\u003e true,\n  ['show_active']: (todo) =\u003e !todo.completed,\n  ['show_completed']: (todo) =\u003e todo.completed\n};\n\nconst filteredListLens = makeFilteredListLens(\n  'todos',\n  (item, state) =\u003e TODO_FILTER_FUNCTIONS[state.filter](item),\n  'id'\n);\n\n// Somewhere when rendering:\n\u003cCollection lens={filteredListLens} itemComponent={TodoItem} /\u003e\n```\n\nThe above will only show the filtered subset of the collection and will merge any state changes to the source collection. Please note that this `lens` is to isolate the collection, not its items - those are still managed internally with some internal `itemLens`.\n\nThe `makeFilteredListLens` function has this signature:\n\n```js\n(stateProp, filterPredicate, equals) =\u003e Lens\n```\nwith all arguments required.\n\n- `stateProp` is just a string that defines which piece of state the filtered collection should be calculated from. While it wouldn't be neccessary for `get` part of the `lens`, we need it for `set`, because filtered collection is a computed value and doesn't reside on the state directly, so we need to let it know which piece of state is to update.\n\n  Its going to be the same what you'd otherwise set as `\u003cCollection\u003e` `lens` prop string shortcut, should you want to show an entire collection without filtering.\n\n- `filterPredicate` is a function of a signature:\n  ```js\n  (itemState, state) =\u003e boolean\n  ```\n  which is the heart of this feature - it decides whether to include or excluded the item into/from the filtered collection. Return `true` for the item to be included (its just a regular `Array.prototype.filter` behind the scenes). Particular item state is passed as a first argument but there's also a second argument, `state`, that is the entire `state` object, where your collection property resides...\n  \n  Wait, WAT! Why would lens know about the state that is beyond of collection state itself? Well, since your state is fractal and you're keeping your list there, chances are you're going to keep the **filtering** and **pagination** metadata from that level on as well. This might seems confusing at first, so feel free to check how it's used in our [TodoMVC](https://github.com/VasilioRuzanni/react-cycle-connect/tree/master/examples/todomvc) example.\n\n- `equals` is a predicate to check whether the two items are equal:\n  ```js\n  (itemState1, itemState2) =\u003e boolean\n  ```\n\n  Should return `true` if two item's states should be considered equal. Its such a common thing to just provide something like\n  ```js\n  (item1, item2) =\u003e item1.id === item2.id\n  ```\n\n  that there's a `string` shortcut for it, which accepts the attribute name, e.g., `id`:\n  ```js\n  makeFilteredListLens('someStateProps', ..., 'id')\n  ```\n\nNote that this is only about filtering the state data on isolation, its not about rendering. `\u003cCollection\u003e` handles rendering no matter what `lens` is in use and you can also use the created `lens` on your own, not necessarily with `\u003cCollection\u003e`.\n\n\n### Testing\n\nThis is more or less straightforward here - `react-cycle-connect` doesn't really have any `react-cycle-connect`-ish code to write, so it boils down to Cycle.js testing (take a look at [`@cycle/time`](https://github.com/cyclejs/cyclejs/tree/master/time) here) as well as React testing with, e.g., [Jest](https://facebook.github.io/jest/docs/en/tutorial-react.html) and [Enzyme](https://github.com/airbnb/enzyme).\n\n**[TODO: To be expanded with examples and practices]**\n\n\n### TypeScript support\n\n[WIP]\n\nQuick note: `react-cycle-connect` is itself written in TypeScript and export lots of types, both internally used and those intended to be used in the userland. Type-annotated examples and suggested practices are coming up!\n\n\n## API reference\n\n[TODO]\n\nQuick note: [Guide](#guide) covers most (if not all) of the public API of the lib, so feel free to check that out in the meantime.\n\n\n## Alternatives / Competitors\n\n#### [cycle-react](https://github.com/pH200/cycle-react)\n\nThis is one of the first attempts to use \"Cycle pattern\" with React. It doesn't have any references to Cycle.js itself, but it nicely reimplements the pattern, so the architecture is somewhat similar. Its using much more Cycle.js way of handling markup, which you're building inside Cycle program itself there, which isn't the case with `react-cycle-connect` where there is more explicit boundary between React and Cycle.\n\nIts also where the concept of `interactions` came from to `react-cycle-connect` (though, orchestrated differently). Only meant to be used with `RxJS 4` and `RxJS 5`. \n\nDoesn't maintain the tree of Cycle.js programs, focusing on having the \"Cycle pattern\" at component level instead with a different public API surface.\n\nLooks quite robust in what it does, so definitely take a look at it.\n\n#### [recycle.js](https://recycle.js.org/)\n\nThis is a really cool one, another reimplementation of \"Cycle pattern\" in React, but this time its closer to pure Cycle.js when it comes to event handling with view being a pure readonly representation of state.\n\nThe downside is that it explicitly monkey-patches the `React.createElement` to achieve Cycle.js style of event handling.\n\nIts approach also resembles [Elm](http://elm-lang.org/) and [`hyperapp`](https://hyperapp.js.org/) in that its `view`, `dispatch`, `update`, etc sections are explicitly configured, whereas you just call functions from functions in Cycle.js (and `react-cycle-connect`).\n\n\n#### [redux-cycles](https://github.com/cyclejs-community/redux-cycles)\n\nNot really an alternative, since it doesn't allow to use Cycle.js for React component dataflow. Its rather a set of drivers for `redux`, supposed to provide an ability to use Cycle.js for handling side effects in [Redux](https://redux.js.org/)-based app.\n\nDefinitely consider it if all you need is managing Redux async actions' side-effects.\n\nLike `react-cycle-connect`, it assumes the use of the real Cycle.js libs. This means that it could well be a complement to `react-cycle-connect` if you decide to use Redux as a state container in `react-cycle-connect` (and not, e.g., `cycle-onionify`).\n\n\n## FAQ\n\n[TODO]\n\n\n## Roadmap\n\n- Streamline the API\n- JSDoc for the entire codebase\n- Full test coverage\n- Optimize the re-rendering (the entire props update pipeline)\n- `RxJS` and `most.js` support (looking into how [Callbags](https://github.com/staltz/callbag-basics) would possibly make their way into Cycle.js, thus making it more reactive-lib agnostic).\n- `preact` and `inferno` support (and also possibly `Vue`, in which case it might be renamed somehow)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvasilioruzanni%2Freact-cycle-connect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvasilioruzanni%2Freact-cycle-connect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvasilioruzanni%2Freact-cycle-connect/lists"}