
Security News
Software Engineering Daily Podcast: Feross on AI, Open Source, and Supply Chain Risk
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.
component-from-stream
Advanced tools
lightweight (1kb gz) component-from-stream on steroids: create a React-like component from any React-compatible library, that sources its props from an observable stream and supports middleware.
create a React-like component from any React-compatible library, that sources its props from an observable stream.
backwards-compatible with, and based on component-from-stream
from recompose,
with the following enhancements:
React-compatible library,React-like Component class,
e.g. PREACT or Inferno.component-from-stream-redux.props dispatcher instead of the default dispatcher,component-from-stream-redux operator.componentWillUnmount.props object,compatible with observable libraries such as RxJS
or MOST
see the full example in this directory.
run the example in your browser locally with npm run example
or online here.
the component-from-stream example
from recompose can be refactored as follows
to separate view rendering from reactive behaviour:
const Counter = componentFromStream(pipe(newCounterOperator(), map(render)))
function render({ count, onClickIncrement, onClickDecrement, ...attrs }) {
return (
<pre {...attrs}>
Count: {count}
<button onClick={onClickIncrement}><b>+</b></button>
<button onClick={onClickDecrement}><b>-</b></button>
</pre>
)
}
function newCounterOperator () {
const diff$ = new Subject()
const onClickIncrement = () => diff$.next(1)
const onClickDecrement = () => diff$.next(-1)
const count$ = diff$.pipe(
startWith(0),
scan((count, n) => count + n, 0)
)
return pipe(
combineLatest(count$),
map(([ props, count ]) => ({
count,
onClickIncrement,
onClickDecrement,
...props
}))
)
}
function pipe (...operators) {
return function (q$) {
return q$.pipe(...operators)
}
}
this module supports the following shorthand for this approach:
const Counter = componentFromStream(render, newCounterOperator)
separation of reactive behaviour from view rendering yields a number of advantages:
props = no DOM involved.component-from-stream factory signaturesthe component-from-stream factory is not directly exposed by this module.
instead, a higher-level factory is exposed for injecting the following dependencies:
Component from a React-like library,
e.g. PREACT or Inferno.RxJS
or MOST.this higher-level factory returns the required component factory
after injection of the supplied dependencies.
it is typically only required once in a project,
the resulting component-from-stream factory being exposed to the project's
other modules:
import createComponentFromStreamFactory from 'component-from-stream'
import { Component } from 'inferno'
import { from } from 'rxjs'
// component-from-stream factory based on Inferno and RxJS
export default createComponentFromStreamFactory(Component, from)
in addition to the original component-from-stream factory signature
from recompose,
the example from the previous section illustrates
the additional dual-argument signature,
shorthand for separating view and reactive operator behaviour.
in this example, the reactive operator factory ignores its arguments.
however, that factory is nonetheless called with a number of arguments,
as detailed in the OperatorFactory type declaration below.
the first of these arguments is a StreamableDispatcher object,
which provides hooks into the internal dispatching mechanism.
this allows for more complex feedback control of the reactive operator chain.
this is most useful with the component-from-stream factory's third signature,
which takes at least three arguments
as specified in the ComponentFromStreamFactory interface declaration below.
in this configuration,
OperatorFactory factories.
the operators instantiated by these factories are composed from left to right
to generate the component's reactive operator,
that maps the dispatched objects to view props.see the component-from-stream-redux
module for an example implementation of this extended signature.
import { Subscribable } from 'rx-subject'
export { Subscribable }
export default function createComponentFromStreamFactory<C extends Component<N, any, any>, N>(
ComponentCtor: new (props: any, context?: any) => C & Component<N, any, any>,
fromESObservable: <T, O extends Subscribable<T>>(stream: Subscribable<T>) => O,
opts?: Partial<ComponentFromStreamOptions>
): ComponentFromStreamFactory<C, N>
export default function createComponentFromStreamFactory<C extends Component<N, any, any>, N>(
ComponentCtor: new (props: any, context?: any) => C & Component<N, any, any>,
fromESObservable: <T, O extends Subscribable<T>>(stream: Subscribable<T>) => O,
toESObservable: <T, O extends Subscribable<T>>(stream: O) => Subscribable<T>,
opts?: Partial<ComponentFromStreamOptions>
): ComponentFromStreamFactory<C, N>
export interface ComponentFromStreamFactory<C extends Component<N, any, any>, N> {
<P = {}>(operator: Operator<P, N>): ComponentFromStreamConstructor<C, N>
<P = {}, Q = P>(
render: (props: Q) => N,
factory: OperatorFactory<P, P, Q>
): ComponentFromStreamConstructor<C, N>
<P = {}, Q = P, A = P>(
render: (props: Q) => N,
project: Mapper<P, A>,
operator: OperatorFactory<A, A, any>,
...operators: OperatorFactory<A, any, any>[]
): ComponentFromStreamConstructor<C, N>
}
export interface ComponentFromStreamOptions {}
export interface ComponentFromStreamConstructor<C extends Component<N, any, any>, N> {
new <P = {}, Q = P>(props?: P, context?: any): C & ComponentFromStream<N, P, Q>
}
export interface ComponentFromStream<N, P = {}, Q = P>
extends Component<N, P, PropsState<Q>> {
componentWillMount(): void
componentWillReceiveProps(nextProps: Readonly<P>, nextContext: any): void
componentWillUnmount(): void
shouldComponentUpdate(props: Readonly<P>, state: Readonly<PropsState<Q>>): boolean
}
export interface ComponentConstructor<N> {
new <P = {}, S = {}>(props: P, context?: any): Component<N, P, S>
}
export interface Component<N, P = {}, S = {}> {
setState(state: Reducer<S, P> | Partial<S>, cb?: () => void): void
render(props?: P, state?: S, context?: any): N | void
props: Readonly<P>
state: Readonly<S | null>
context: any
}
export interface PropsState<Q> {
props: Q
}
export declare type Mapper<P, A = P> = (props: P) => A
export declare type OperatorFactory<
A = void,
I = {},
O = I,
Q extends Subscribable<I> = Subscribable<I>,
S extends Subscribable<O> = Subscribable<O>
> = (
dispatch?: StreamableDispatcher<A>,
fromESObservable?: <T, O extends Subscribable<T>>(stream: Subscribable<T>) => O,
toESObservable?: <T, O extends Subscribable<T>>(stream: O) => Subscribable<T>
) => Operator<I, O, Q, S>
export declare type Operator<
I = {},
O = I,
Q extends Subscribable<I> = Subscribable<I>,
S extends Subscribable<O> = Subscribable<O>
> = (q$: Q) => S
export interface StreamableDispatcher<A, S extends Subscribable<A> = Subscribable<A>> {
next(val: A): void
from<E extends Subscribable<A>>(source$: E): void
source$: S
}
export declare type Reducer<A, V> = (acc: A, val: V) => A;
export declare function identity<T>(v: T): T
Symbol.observableThis module expects Symbol.observable to be defined in the global scope.
Use a polyfill such as symbol-observable
and if necessary a Symbol polyfill.
Check the symbol-observable-polyfill script
for an example of how to generate the standalone polyfill,
which can than be loaded from a script tag,
or simply add import 'symbol-observable' at the top of your project's main file.
although this library is written in TypeScript, it may also be imported into plain JavaScript code: modern code editors will still benefit from the available type definition, e.g. for helpful code completion.
Copyright 2018 Stéphane M. Catala
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and Limitations under the License.
FAQs
lightweight (1kb gz) component-from-stream on steroids: create a React-like component from any React-compatible library, that sources its props from an observable stream and supports middleware.
We found that component-from-stream demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.

Security News
GitHub has revoked npm classic tokens for publishing; maintainers must migrate, but OpenJS warns OIDC trusted publishing still has risky gaps for critical projects.

Security News
Rust’s crates.io team is advancing an RFC to add a Security tab that surfaces RustSec vulnerability and unsoundness advisories directly on crate pages.