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

conduit-rxjs-react

v0.7.2

Published

Conduit utilities for connecting RxJS streams to React.

Downloads

10

Readme

Conduit RxJS React

Conduit utilities for connecting RxJS streams to React.

Installation

Install peer dependencies:

Then install this package.

npm install conduit-rxjs-react

API

connect

Create a React component connected to a source stream.

Usage: connect(component, source, ...selectorArguments)

Arguments:

  • component: Functional React Component|Class React Component
  • source: Object|Stream|Function If source is an object, the component sets the initial state as the object and doesn't render anymore. If source is a stream, the component will update when the stream emits. If wanting access to lifecycle methods, source should be a "selector" function which returns an object or stream.
  • selectorArguments: ...Argument list of strings (optional). See Customizing the selector function for usage.

Returns: React component

Connecting to an object

If source is an object, the component sets the initial state as the object but doesn't render anymore.

import React from 'react'
import { render } from 'react-dom'
import { connect } from 'conduit-rxjs-react'

const initialState = {
  name: 'Bob'
}

function Hello(props) {
  return (
    <div>
      Hello {props.name}
    </div>
  )
}

const ConnectedHello = connect(Hello, initialState)

render(<ConnectedHello />, document.querySelector('#app'))

Using connect in this way is generally discouraged, since it's simpler to just spread initialState on the component.

render(<Hello {...initialState} />, document.querySelector('#app'))

Connecting to a stream

If source is a stream, the component will update when the stream emits.

To maximize performance when rendering, the component updates only when source emits a value and when the browser is ready. When source emits a value, the component informs the browser via requestAnimationFrame that a repaint will occur. If source emits more values while the component waits for the callback to be called, it retains only the latest value. Once the callback is called, rendering is triggered by setting the internal state of the component with the latest value of source, via setState().

Part 5 of Introduction demonstrates how to connect a stream to a component.

import React from 'react'
import { render } from 'react-dom'
import { interval, map, startWith } from 'rxjs'
import { connect } from 'conduit-rxjs-react'

const timerState$ = interval(1000).pipe(
  map((intervalValue) => intervalValue + 1),
  startWith(0),
  map((secondsElapsed) => ({ secondsElapsed }))
)

function Timer(props) {
  return (
    <div>Seconds Elapsed: {props.secondsElapsed}</div>
  )
}

const ConnectedTimer = connect(Timer, timerState$)

render(<ConnectedTimer />, document.querySelector('#app'))

Connecting to lifecycle methods

If source is an object or stream, source is shared with any number of component instances that may be mounted. However, if wanting to ensure that every instance is isolated, source should be a function. In addition, source as a function gives you access to each instance's lifecycle methods. Generally, the name of this function is called selector, because you select what should be connected to the component.

Usage: function selector(props$, componentDidRender, componentWillUnmount) {...}

Arguments:

  • props$: Stream A stream of prop updates. This is initialized with the initial value of props.
  • componentDidRender: Function Pass it a function that will be called whenever the component next renders. This could occur both after mounting and after updates, but it is only called once. If this is called multiple times between renders, all passed functions will be queued and called in sequence after the next render. This is particularly useful when wanting to do some conditional DOM side effects, such as placing focus on an element after it is rendered.
  • componentWillUnmount: Function Pass it a function that will be called whenever the component unmounts. Similar to componentDidRender, multiple calls are queued and will be called in sequence during unmount. This is useful for cleanup, such as unsubscribing from subscriptions made within the selector function.

Example:

import React from 'react'
import { render } from 'react-dom'
import { combineLatest, interval, map, startWith, switchMap, tap } from 'rxjs'
import { connect } from 'conduit-rxjs-react'

function selector(props$, componentDidRender, componentWillUnmount) {
  // Calculate the lifespan of the component.
  const mountTime = new Date()
  componentWillUnmount(() => {
    const unmountTime = new Date()
    const lifespanSeconds = Math.ceil((unmountTime - mountTime) / 1000)
    console.log(`Component lifespan: ${lifespanSeconds} seconds`)
  })
  // Reset the counter whenever the duration prop updates.
  const count$ = props$.pipe(
    map(({ duration }) => Math.parseInt(duration)),
    startWith(1000),
    switchMap((duration) =>
      interval(duration).pipe(
        map((i) => i + 1),
        startWith(0)
      )
    ),
    // When the count is even, focus on the even button.
    // When the count is odd, focus on the odd button.
    tap((count) => {
      const id = `focusButton${count % 2 === 0 ? 'Even' : 'Odd'}`
      componentDidRender(() => document.getElementById(id).focus())
    })
    map((count) => ({ count }))
  )
  return combineLatest(props$, count$).pipe(
    // Merge the array of objects into a single object.
    // This is the component's state.
    map((source) => source.reduce((acc, value) => ({ ...acc, ...value }), {}))
  )
}

function Count(props) {
  return (
    <div>
      <div>Count: {props.count}</div>
      <button id="focusButtonEven">Even</button>
      <button id="focusButtonOdd">Odd</button>
    </div>
  )
}

const ConnectedCount = connect(Count, selector)

render(<ConnectedCount duration={5000} />, document.querySelector('#app'))

Customizing the selector function

By default, connect will ensure props$, componentDidRender, and componentWillUnmount are available whenever source is a function. If you don't need all these options, then indicate which ones you need by listing the names of options as additional string arguments for connect. As a performance gain, other selector options will never be initated. This is also useful if you'd prefer the options to be ordered differently.

Default options:

function selector(props$, componentDidRender, componentWillUnmount) {
  ...
}

// This:
const ConnectedCount = connect(Count, selector)

// Is the same as this:
const ConnectedCount = connect(Count, selector, 'props$', 'componentDidRender', 'componentWillUnmount')

Use a subset of options:

function selector(componentWillUnmount) {
  ...
}
const ConnectedCount = connect(Count, selector, 'componentWillUnmount')

Reorder options:

function selector(componentDidRender, props$) {
  ...
}
const ConnectedCount = connect(Count, selector, 'componentDidRender', 'props$')