Gathering detailed insights and metrics for remcycle
Gathering detailed insights and metrics for remcycle
Gathering detailed insights and metrics for remcycle
Gathering detailed insights and metrics for remcycle
a Cycle.js-based component factory and set of higher-order-components built on cycle-react-driver, cycle-redux-driver, and most
npm install remcycle
Typescript
Module System
Node Version
NPM Version
TypeScript (98.24%)
JavaScript (1.76%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
3 Stars
142 Commits
1 Forks
1 Branches
1 Contributors
Updated on Feb 26, 2019
Latest Version
0.2.21-beta.1
Package Id
remcycle@0.2.21-beta.1
Unpacked Size
343.48 kB
Size
70.45 kB
File Count
259
NPM Version
5.1.0
Node Version
6.9.2
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
16
1
a Cycle.js-based component factory and set of higher-order-components built on cycle-react-driver, cycle-redux-driver, and most
npm install --save remcycle
1import mapProps from 'remcycle/es2015/hoc/mapProps'; // HOCs 2import createComponent from 'remcycle/es2015/createComponent'; // helpers 3import { shallowEquals } from 'remcycle/es2015/util'; // utilities
A higher-order component (HOC) is a function that takes in a Cycle.js component and returns a Cycle.js component.
This pattern makes HOCs composable and allows us to use Ramda's compose
or pipe
functions to stitch multiple HOCs together into a single, larger HOC.
The following HOC factories and utilities are provided by this library:
NOTE: A few HOC factories have two versions, one that exposes single props
or action
objects and another that exposes the raw props
source stream, action
streams and component sources - use the latter for more granular control over stream manipulation and creation.
mapProps
1mapProps(propsMapper: (props: {}) => {}): HigherOrderComponent
Transforms props
to be passed into the base component as the props
source stream.
Useful as a base HOC for higher-level HOCs for transforming props (e.g. renaming, omitting, etc).
1mapProps(({ count, ...props }) => ({ 2 value: count, // renames the count prop, omits the rest from the props source stream 3}));
mapPropsStream
1mapPropsStream( 2 propsStreamMapper: (propsSource: Stream<{}>) => Stream<{}>, 3): HigherOrderComponent
Same as mapProps
, but transforms the props
source stream (or of({})
if props
source is undefined
).
Useful as a base HOC for higher-level HOCs for more granular control over transforming props (e.g. throttling, filtering, etc).
1mapPropsStream(propsSource => {
2 return propsSource
3 .map(({ count, ...props }) => ({
4 value: count, // same example as above
5 }));
6});
withProps
1withProps(
2 propsOrPropsCreator: {} | (props: {}) => {} | void,
3): HigherOrderComponent
4
5withProps(
6 watchedPropNames: string | string[],
7 propsCreator: (props: {}) => {} | void,
8): HigherOrderComponent
Merges into the props
stream new props
, either created from an object or a function that returns new props
.
Either:
props
to be merged with upstream props
, or a function that transforms upstream props
into new props
to be mergedprops
to watch for changes (using shallowEquals
), and when they have changed, run the propsCreator
on upstream props
to return new props
to be merged.If propsCreator
returns undefined
, upstream props
are emitted unchanged.
Useful for adding new props
, overwriting upstream props
, or for merging in new props
that are expensive to create via the propsCreator
.
NOTE: the watching behaviour is only included in this HOC factory for backwards-compatibility reasons - if you want to control when you create new props
, you should use withPropsOnChange
.
1// merging props from props object
2withProps({ name: 'Selector' });
3
4// merging props from props creator
5withProps(({ val }) => ({ value: val })); // simple renaming of props
6
7// merging props from props creator on props change
8withProps(
9 [ 'params.prop1', 'dependencyProp' ], // can take multiple and/or nested prop names
10 ({ dependencyProp }) => {
11 // ... perform expensive operations here
12 return {
13 // ... new props to merge into upstream props
14 };
15 },
16);
withPropsOnChange
1withPropsOnChange( 2 namesOrPredicate: string | string[] | (currentProps: {}, previousProps: {}) => boolean, 3 propsCreator: (props: {}) => {} | void, 4): HigherOrderComponent
Accepts name(s) of props
to watch for changes (using shallowEquals
) or a predicate
function applied to currentProps
and previousProps
, and when the listed props
have changed (or when the predicate
returns true
), run the propsCreator
on upstream props
to return new props
to be merged.
If propsCreator
returns undefined
, upstream props
are emitted unchanged.
Useful for merging in new props
that are expensive to create via the propsCreator
.
1// merging props from props creator on props change 2withPropsOnChange( 3 [ 'params.prop1', 'dependencyProp' ], // can take multiple and/or nested prop names 4 ({ dependencyProp }) => { 5 // ... perform expensive operations here 6 return { 7 // ... new props to merge into upstream props 8 }; 9 }, 10); 11 12// merging props from props creator based on predicate's return value 13withPropsOnChange( 14 ({ dependencyProp: current }, { dependencyProp: previous }) => { 15 // only when this prop is unequal to it's previous value 16 return current !== previous; 17 }, 18 ({ dependencyProp: current }) => { 19 // ... perform expensive operations here 20 return { 21 // ... new props to merge into upstream props 22 }; 23 }, 24);
withState
1withState<T>( 2 stateName: string, 3 initialStateOrCreator: T | (props: {}) => T, 4 actionReducers?: { 5 [actionType: string]: 6 (state: T, action: FluxStandardAction<any>, props: {}) => T, 7 }, 8 propReducers?: { 9 [propNames: string | string[]]: 10 (state: T, props: {}) => T, 11 }, 12): HigherOrderComponent
Creates, merges into the props
source stream, and maintains the state of a new/existing prop
using the reducer pattern.
initialStateOrCreator
is either the initial state of the prop
or a function that creates the initial state from the current props
.
actionReducers
select the REDUX
source stream using the given actionType
and on each action, invokes the reducer on the state
, the action
, and the current props
.
propReducers
watch the given propName(s)
(possibly nested) for changes (using shallowEquals
) and when changed, invokes the reducer on the state
and current props
.
1withState( 2 'count', 3 ({ count }) => count !== undefined ? count : 0, 4 { 5 'Counter/increment': (count, { payload }) => count += payload, 6 'Counter/decrement': (count, { payload }) => count -= payload, 7 'Counter/reset': _ => 0, 8 }, { 9 count: (_, { count }) => count // parent is resetting the state 10 }, 11);
defaultProps
1defaultProps({ [propName: string]: any }): HigherOrderComponent
Merges in a set of props
, unless they already exist in the props
source stream. Like withProps
, but upstream props
already in the props
source stream take precedence.
1// if parent didn't provide a `value` prop for the <input type="number" /> tag, set it to 0 as a reasonable default
2defaultProps({
3 type: 'number',
4 value: 0,
5});
omitProps
1omitProps(string | string[]): HigherOrderComponent
Omits props from the props
source stream.
1omitProps([ 'isLoading' ]); // omits the prop `isLoading`, perhaps because it wasn't needed
doOnPropsChange
1doOnPropsChange( 2 propsCreator: (props: {}) => {} | void, 3): HigherOrderComponent 4 5doOnPropsChange( 6 watchedPropNames: string | string[], 7 propsCreator: (props: {}) => {} | void, 8): HigherOrderComponent 9 10doOnPropsChange( 11 namesOrPredicate: string | string[] | (currentProps: {}, previousProps: {}) => boolean, 12 propsCreator: (props: {}) => {} | void, 13): HigherOrderComponent
Syntactically-identical to withProps
or withPropsOnChange
, but is recommended to be used when performing imperative/mutable/impure changes to existing props
.
mapActions
1mapActions<T>( 2 { [actionType: string]: 3 (action: FluxStandardAction<T>, props: {}) => FluxStandardAction<T> | void 4 } 5): HigherOrderComponent
Transforms an action
of the given actionType
with the current props
. If the transform returns undefined
, the action
is filtered out of the action
stream.
Useful for augmenting action
payloads or filtering out action
s with invalid or undesirable payloads.
1// filters out any values greater than the `maxAllowable` for the <input type="number"/> tag 2mapActions({ 3 'Input/change': (action, { maxAllowable }) => { 4 return (Number(action.payload) > maxAllowable) ? void 0 : action; 5 }, 6});
mapActionStreams
1mapActionStreams<T>( 2 { [actionType: string]: 3 (action: Stream<FluxStandardAction<T>>, sources: {}) => Stream<FluxStandardAction<T>> 4 } 5): HigherOrderComponent
Identical to mapActions
, except the action
stream creator function takes the action
stream of the given actionType
and all of the component's sources, returning the new action
stream.
1// same example as above 2// filters out any values greater than the `maxAllowable` for the <input type="number"/> tag 3mapActionStreams({ 4 'Input/change': (action$, { props: propsSource = of({}) }) => { 5 const maxAllowable$ = propsSource.map(({ maxAllowable }) => maxAllowable); 6 7 return action$ 8 .sample((action, maxAllowable) => ([ action, maxAllowable ]), action$, maxAllowable$) 9 .filter(([ { payload }, maxAllowable ]) => Number(payload) <= maxAllowable) 10 .map(([ action ]) => action) 11 .multicast(); 12 }, 13});
withActions
1withActions<T, U>( 2 { [listenedActionType: string]: 3 { [emittedActionType: string]: 4 (listenedAction: FluxStandardAction<T>, props: {}) => FluxStandardAction<U> 5 } 6 } 7): HigherOrderComponent
Multiplexes an action
stream onto another action
stream - action
creator function takes in each listenedActionType
action and current props
and returns an action
of the emittedActionType
. If an action
stream of the emittedActionType
already exists, the returned action
s will be merged into that stream.
Useful for emitting an additional action
when a given action is emitted, or generally mapping a particular source to a new action
stream.
1// maps an Input component change action to a new action specific to the MaxInput component
2withActions({
3 'Input/change': {
4 'MaxInput/set': ({ payload }) => setMaxInput(payload),
5 },
6});
withActionStreams
1withActionStreams<T, U>( 2 { [listenedActionType: string]: 3 { [emittedActionType: string]: 4 (listenedActionStream: Stream<FluxStandardAction<T>>, sources: {}) => Stream<FluxStandardAction<U>> 5 } 6 } 7): HigherOrderComponent
Identical to withActions
, except the action
stream creator function takes the action
stream of the given listenedActionType
and all of the component's sources, returning the new action
stream. If an action
stream of the emittedActionType
exists, the returned action
stream will be merged into that stream.
1// same example as above, but debounces the emitted actions before emitting
2// maps an Input component change action to a new action specific to the MaxInput component
3withActionStreams({
4 'Input/change': {
5 'MaxInput/set': (inputChangeAction$, { Time }) => inputChangeAction$
6 .thru(Time.debounce(250))
7 .map(({ payload }) => setMaxInput(payload)),
8 },
9});
10
mapSourcesToActionStreams
1mapSourcesToActionStreams( 2 { [actionType: string]: (sources: {}): ActionStream<any>; } 3): HigherOrderComponent
Helper for mapping sources to new (or merge into existing) action
streams.
1// in event-sourcing parlance, we can map state changes to domain events 2mapSourcesToActionStreams({ 3 [INPUT_CHANGED]: ({ props: propsSource }) => { 4 return propsSource 5 .map(props => props['input']) 6 .map(inputChangedActionCreator) 7 .multicast(); 8 }, 9});
addActionHandlers
1addActionHandlers(
2 { [handlerPropName: string]:
3 { type: string,
4 actionCreator: (props: {}, eventArgs: any | any[]) => FluxStandardAction<any>,
5 actionStreamCreator: (sources: {}, event$: Stream<any>) => Stream<FluxStandardAction<any>>,
6 hold?: boolean,
7 }
8 }
9): HigherOrderComponent
Similar to Redux's mapDispatchToProps
. addActionHandlers
does two things:
props
source stream a handler function of the provided handlerPropName
action
sink stream that emits an action
when the handler is invoked.If you declare the actionCreator
property, the actionCreator
function accepts the current props
and the eventArg
value passed into the handler (or an array of values if the handler is invoked with multiple arguments) and should return the action
of the desired type
.
If you declare the actionStreamCreator
property, the actionStreamCreator
function accepts the component's sources and the stream of eventArgs
emitted when the handler is invoked (again, with a single value or an array values, depending on the number of parameters passed into the handler) and should return a stream of actions
of the desired type
.
The hold
property should be specified as true
(default is false
) if the action
stream should remember it's last action
.
Useful for imperatively generating actions, most commonly from passing the handlers into a React component.
1// emits `'Input/change'` actions when the `onChange` handler is invoked, perhaps in an <input /> component
2addActionHandlers({
3 onChange: {
4 type: 'Input/change',
5 actionCreator: (_, e) => inputChange(e.target.value),
6 },
7});
mapView
1mapView(
2 viewMapper: (vtree: ReactElement<any>, props: {}) => ReactElement<any>,
3 propsToPluck?: string | string[],
4): HigherOrderComponent
Wraps a component's React element sink or it's child's React sink with additional React elements.
Optionally, allows you to specify props
to pluck from the props
source stream to use for rendering the wrapper component (defaults to '*'
which then passes all props
to the viewMapper
).
1const Container = ({ childVtree, className }) => 2 <div className={className}> 3 {childVtree} 4 </div>; 5 6mapView( 7 (vtree, { className }) => Container({ childVtree: vtree, className }), 8 [ 'className' ], 9);
withCollection
1withCollection( 2 collectionName: string, 3 initialCollectionOrCreator: Collection | (sources: {}) => Collection, 4 actionReducers?: { 5 [actionType: string]: 6 (collection: Collection, action: FluxStandardAction<any>, props: {}, sources: {}) => Collection, 7 }, 8 propReducers?: { 9 [propNames: string | string[]]: 10 (collection: Collection, props: {}, sources: {}) => Collection, 11 }, 12): HigherOrderComponent
Creates and maintains the state of a Most.js Collection, returning a stream of the collection's state and merging it into the component's sources (so that it can be manipulated in subsequent HOCs).
initialCollectionOrCreator
is either the initial collection or a function that creates the initial collection from the sources.
actionReducers
select a REDUX
source stream using the given actionType
and on each action, invokes the reducer on the collection, the action
, the current props
and all sources.
propReducers
watch the given propName(s)
(possibly nested) for changes (using shallowEquals
) and when changed, invokes the reducer on the collection, current props
and all sources.
1// manages a collection of children `TodoItem` components and their state 2withCollection('todoItems', Collection(TodoItem), { 3 'TodoList/add': (todos, { payload: text }) => { 4 const props$ = of({ text, isComplete: false }); 5 6 return todos.add({ ...sources, props: props$ }); 7 }, 8 'TodoList/toggleAll': (todos, { payload: allChecked }) => { 9 return Array(todos.size).fill(0) 10 .reduce((newTodos, _, index) => { 11 const todo = todos.getAt(index); 12 const props$ = todo.input.props 13 .map(props => ({ ...props, isComplete: allChecked })); 14 15 return newTodos.setAt(index, { ...todo.input, props: props$ }); 16 }, todos); 17 }, 18});
addActionTypes
1addActionTypes(
2 componentName: string,
3 { [actionType: string]: PropType }
4): HigherOrderComponent
Augments the Redux action
sink, performing prop-type checks on each action
payload.
1addActionTypes('Input', { 2 'Input/change': PropTypes.string, 3});
addPropTypes
1addPropTypes(
2 componentName: string,
3 { [propName: string]: PropType }
4): HigherOrderComponent
Augments the props
source stream, performing prop-type checks on the props
object.
1addPropTypes('Input', {
2 value: PropTypes.string.isRequired,
3 type: PropTypes.string,
4});
logActions
1logActions( 2 sinkLogger: ({ [actionType: string]: Stream<FluxStandardAction<any>> }) => void, 3 actionLoggers: { [actionType: string]: (<FluxStandardAction<any>) => void }, 4): HigherOrderComponent
Takes in an optional sinksLogger
function which logs all action
streams in the Redux sink, and an object of logging functions for any given actionType
.
1logActions(::console.log, {
2 'Input/change': ::console.log,
3});
logProps
1logProps( 2 propsLogger: (props: {}) => void, 3): HigherOrderComponent
Logs all props
from the upstream props
source stream.
1logProps(::console.log);
createComponent
1createComponent({
2 main: Component;
3 name?: string;
4 handlers?: Handlers; // same input as `addActionHandlers`
5 children?: {
6 keys: string;
7 sources: HigherOrderComponent | HigherOrderComponent[];
8 sinks: HigherOrderComponent | HigherOrderComponent[];
9 };
10 wrapper?: HigherOrderComponent;
11 sinks?: HigherOrderComponent | HigherOrderComponent[];
12 sources?: HigherOrderComponent | HigherOrderComponent[];
13 actionTypes?: { [actionType: string]: PropType };
14 propTypes?: { [propName: string]: PropType };
15 isolate?: false | ((Sources: any) => (null | string | {})) | null | string | {};
16}): Component
A factory function for creating Cycle.js components from a series of HOCs.
Each optional property results in an HOC and is applied in the following order:
main
: the base component to be wrappedhandlers
: React function callbacks to be passed as props
(usually, only used with view
) with resultant action
s emittedchildren
: object (soon to be array of objects) of HOCs to define what children should be rendered and how their collective state should be maintainedwrapper
: HOC defining any low level source or sink transformations required for this component or it's childrensinks
: HOC or array of HOCs describing sink transformationssources
: HOC or array of HOCs describing source transformationsisolate
: function returning the isolation configuration to be applied to all instances of this componentBy applying these HOCs in this order, we get the resulting mental model:
props
actions
(from the actionCreator
or actionStreamCreator
function) using the most-complete props
main
and/or children
Say we want to wrap the great react-select Select
component...
1import React from 'react'; 2import createComponent from 'remcycle/es2015/createComponent'; 3import { fromReactDOMComponent } from '@sunny-g/cycle-react-driver/es2015/dom'; 4 5const main = fromReactDOMComponent(Select, 'REACT'); // maps props to a React sink named 'REACT' 6 7export default createComponent({ 8 name: 'Select', // used for prop-type reporting 9 main: , // can be any Cycle component, but creating one from a React component 10 isolate: () => Math.random().toString(), // isolation with a random scope 11 handlers: { 12 onChange: { // necessary prop for receiving current selection 13 type: 'Select/change', 14 actionCreator: (_, selection) => ({ 15 type: 'Select/change', 16 payload: selection, 17 error: false, 18 meta: {}, 19 }), 20 }, 21 }, 22 sources: [ 23 defaultProps({ // provides some react-select defaults 24 defaultValue: '', 25 multi: false, 26 name: 'Select', 27 }), 28 29 // manages state of the react-select component's `value` 30 withState('value', ({ defaultValue }) => defaultValue || null, { 31 'Select/change': (_, selection) => selection, 32 }), 33 ], 34 sinks: [], // no need to manipulate sinks 35 propTypes: { // we can define expected `props` to be included in the `props` source 36 multi: PropTypes.bool, 37 name: PropTypes.string, 38 }, 39 actionTypes: { // likewise, we can document the payload types of the `action`s this component emits 40 'Select/change': PropTypes.oneOfType([ 41 PropTypes.string, 42 PropTypes.arrayOf(PropTypes.string), 43 ]), 44 }, 45});
reactSinksCombiner
1type ReactSink = Stream<ReactElement<any>>; 2 3reactSinksCombiner( 4 view: (...vtrees: ReactElement<any>[], props: {}) => ReactElement<any>, 5 propsSource?: Stream<{}>, 6): (...reactSinks: ReactSink[]) => ReactSink
Helper for combining the React sinks of multiple sibling components into a single React sink, but can be used as a shorthand to combine
any set of sinks.
1import reactSinksCombiner from 'remcycle/es2015/reactSinksCombiner'; 2 3function main(sources) { 4 const todoItemOneSinks = TodoItem(sources); 5 const todoItemTwoSinks = TodoItem(sources); 6 7 // props required for the combined React view component 8 const viewProps$ = sources.props.map(({ className }) => ({ className })); 9 10 // the view that combines the vtrees and props 11 const TodoListView = (todoItemOneVtree, todoItemTwoVtree, { className }) => 12 <div className={className}> 13 {todoItemOneVtree} 14 {todoItemTwoVtree} 15 </div>; 16 17 const mainReactSink = reactSinksCombiner(TodoListView, viewProps$)(todoItemOneSinks.REACT, todoItemTwoSinks.REACT); 18 19 return { 20 REACT: mainReactSink, 21 }; 22}
reduxSinksCombiner
1type ReduxSink = Stream<{ [actionType: string]: Stream<FluxStandardAction<any>> }> 2 3reduxSinksCombiner(...reduxSinks: ReduxSink[]): ReduxSink
Helper for merging the Redux sinks of multiple sibling components into a single Redux sink. If multiple action
streams of the same actionType
exist, the streams are merged together.
1import reduxSinksCombiner from 'remcycle/es2015/reduxSinksCombiner'; 2 3function main(sources) { 4 const todoItemOneSinks = TodoItem(sources); 5 const todoItemTwoSinks = TodoItem(sources); 6 7 const mainReduxSink = reduxSinksCombiner(todoItemOneSinks.REDUX, todoItemTwoSinks.REDUX); 8 9 return { 10 REDUX: mainReduxSink, 11 }; 12}
shallowEquals
1shallowEquals(any, any): boolean
Determines if two JS value or reference types are shallowly equal to eachother (using ===
). If an array
or object
, strict equality is applied to all elements/properties. Directly exported from the shallow-equals library.
1import { shallowEquals } from 'remcycle/es2015/util'; 2 3shallowEquals({ a: 1 }, { a: 1 }); // true 4shallowEquals({ a: 1 }, { b: 1 }); // false
tsc
and webpack
is correctISC
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
license file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
85 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-06-30
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More