refract-xstream
Advanced tools
Comparing version 2.0.0-rc.3 to 2.0.0
235
index.es.js
import xs from 'xstream'; | ||
import dropRepeats from 'xstream/extra/dropRepeats'; | ||
import $$observable from 'symbol-observable'; | ||
import { isValidElement, createElement, Component } from 'react'; | ||
@@ -54,2 +56,43 @@ | ||
var MOUNT_EVENT = '@@refract/event/mount'; | ||
var UNMOUNT_EVENT = '@@refract/event/unmount'; | ||
var DataType; | ||
(function (DataType) { | ||
DataType["EVENT"] = "event"; | ||
DataType["PROPS"] = "props"; | ||
DataType["CALLBACK"] = "callback"; | ||
})(DataType || (DataType = {})); | ||
var isEvent = function (eventName) { return function (data, index) { | ||
return data.type === DataType.EVENT && | ||
data.payload.name === eventName; | ||
}; }; | ||
var isProps = function (data) { return data.type === DataType.PROPS; }; | ||
var isCallback = function (propName) { return function (data) { | ||
return data.type === DataType.CALLBACK && | ||
data.payload.name === propName; | ||
}; }; | ||
var createEventData = function (name, value) { return ({ | ||
type: DataType.EVENT, | ||
payload: { | ||
name: name, | ||
value: value | ||
} | ||
}); }; | ||
var createPropsData = function (props) { return ({ | ||
type: DataType.PROPS, | ||
payload: props | ||
}); }; | ||
var createCallbackData = function (name, args) { return ({ | ||
type: DataType.CALLBACK, | ||
payload: { | ||
name: name, | ||
args: args | ||
} | ||
}); }; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var subscribeToSink = function (sink, next, error) { | ||
@@ -62,19 +105,48 @@ return sink.subscribe({ | ||
}; | ||
var createObservable = function (subscribe) { | ||
var unsubscribe; | ||
return xs.create({ | ||
start: function (listener) { | ||
unsubscribe = subscribe(listener); | ||
var createComponent = function (instance, dataObservable, pushEvent) { | ||
var data = function () { return xs.from(dataObservable); }; | ||
return { | ||
mount: data() | ||
.filter(isEvent(MOUNT_EVENT)) | ||
.mapTo(undefined), | ||
unmount: data() | ||
.filter(isEvent(UNMOUNT_EVENT)) | ||
.mapTo(undefined), | ||
observe: function (propName, valueTransformer) { | ||
if (propName && typeof instance.props[propName] === 'function') { | ||
return data() | ||
.filter(isCallback(propName)) | ||
.map(function (data) { | ||
var args = data.payload.args; | ||
return valueTransformer | ||
? valueTransformer(args) | ||
: args[0]; | ||
}); | ||
} | ||
if (propName) { | ||
return data() | ||
.filter(isProps) | ||
.map(function (data) { | ||
var prop = data.payload[propName]; | ||
return valueTransformer ? valueTransformer(prop) : prop; | ||
}) | ||
.compose(dropRepeats()); | ||
} | ||
return data() | ||
.filter(isProps) | ||
.map(function (data) { return data.payload; }) | ||
.compose(dropRepeats(shallowEquals)); | ||
}, | ||
stop: function () { | ||
unsubscribe(); | ||
} | ||
}); | ||
fromEvent: function (eventName, valueTransformer) { | ||
return data() | ||
.filter(isEvent(eventName)) | ||
.map(function (data) { | ||
var value = data.payload.value; | ||
return valueTransformer ? valueTransformer(value) : value; | ||
}); | ||
}, | ||
pushEvent: pushEvent | ||
}; | ||
}; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var configureComponent = function (handler, errorHandler) { return function (aperture, instance, isValidElement$$1, isComponentClass) { | ||
@@ -84,5 +156,5 @@ if (isValidElement$$1 === void 0) { isValidElement$$1 = function () { return false; }; } | ||
instance.state = { | ||
renderEffect: false, | ||
children: null, | ||
props: {}, | ||
decoratedProps: {} | ||
props: {} | ||
}; | ||
@@ -97,3 +169,3 @@ var setState = function (state) { | ||
else { | ||
instance.state = state; | ||
instance.state = __assign({}, instance.state, state); | ||
} | ||
@@ -106,2 +178,3 @@ }; | ||
setState({ | ||
renderEffect: true, | ||
children: effect | ||
@@ -111,15 +184,6 @@ }); | ||
else if (effect && effect.type === PROPS_EFFECT) { | ||
var payload_1 = effect.payload; | ||
var payload = effect.payload; | ||
setState({ | ||
replace: payload_1.replace, | ||
props: payload_1.props, | ||
decoratedProps: Object.keys(payload_1.props || {}).reduce(function (props, propName) { | ||
var prop = payload_1.props[propName]; | ||
var previousProp = instance.state.props[propName]; | ||
if (typeof prop === 'function' && | ||
prop !== previousProp) { | ||
decorateProp(props, prop, propName); | ||
} | ||
return props; | ||
}, {}) | ||
replace: payload.replace, | ||
props: payload.props | ||
}); | ||
@@ -132,14 +196,13 @@ } | ||
}; | ||
var listeners = { | ||
mount: [], | ||
unmount: [], | ||
allProps: [], | ||
props: {}, | ||
fnProps: {}, | ||
event: {} | ||
var decoratedProps = {}; | ||
var listeners = []; | ||
var addListener = function (listener) { | ||
listeners = listeners.concat(listener); | ||
}; | ||
var decoratedProps = {}; | ||
var removeListener = function (listener) { | ||
listeners = listeners.filter(function (l) { return l !== listener; }); | ||
}; | ||
var pushEvent = function (eventName) { return function (val) { | ||
(listeners.event[eventName] || []).forEach(function (listener) { | ||
return listener.next(val); | ||
listeners.forEach(function (listener) { | ||
listener.next(createEventData(eventName, val)); | ||
}); | ||
@@ -156,3 +219,5 @@ }; }; | ||
} | ||
(listeners.fnProps[propName] || []).forEach(function (l) { return l.next(args[0]); }); | ||
listeners.forEach(function (listener) { | ||
listener.next(createCallbackData(propName, args)); | ||
}); | ||
return prop.apply(void 0, args); | ||
@@ -166,59 +231,16 @@ }; | ||
}); | ||
var mountObservable = createObservable(function (listener) { | ||
listeners.mount = listeners.mount.concat(listener); | ||
return function () { return listeners.mount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var unmountObservable = createObservable(function (listener) { | ||
listeners.unmount = listeners.unmount.concat(listener); | ||
return function () { return listeners.unmount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var createPropObservable = function (propName) { | ||
var listenerType = propName | ||
? typeof instance.props[propName] === 'function' | ||
? 'fnProps' | ||
: 'props' | ||
: 'allProps'; | ||
return createObservable(function (listener) { | ||
if (listenerType === 'allProps') { | ||
listener.next(instance.props); | ||
listeners.allProps = listeners.allProps.concat(listener); | ||
return function () { | ||
listeners.allProps.filter(function (l) { return l !== listener; }); | ||
}; | ||
var dataObservable = (_a = { | ||
subscribe: function (listener) { | ||
addListener(listener); | ||
listener.next(createPropsData(instance.props)); | ||
return { unsubscribe: function () { return removeListener(listener); } }; | ||
} | ||
if (listenerType === 'props') { | ||
listener.next(instance.props[propName]); | ||
} | ||
listeners[listenerType][propName] = (listeners[listenerType][propName] || []).concat(listener); | ||
return function () { | ||
listeners[listenerType][propName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var createEventObservable = function (eventName) { | ||
return createObservable(function (listener) { | ||
listeners.event[eventName] = (listeners.event[eventName] || []).concat(listener); | ||
return function () { | ||
listeners.event[eventName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var component = { | ||
mount: mountObservable, | ||
unmount: unmountObservable, | ||
observe: createPropObservable, | ||
event: createEventObservable, | ||
pushEvent: pushEvent | ||
}; | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
}, | ||
_a); | ||
var component = createComponent(instance, dataObservable, pushEvent); | ||
var sinkObservable = aperture(instance.props)(component); | ||
var sinkSubscription = subscribeToSink(sinkObservable, finalHandler(instance.props), errorHandler ? errorHandler(instance.props) : undefined); | ||
var sendNext = function (prevProps) { | ||
Object.keys(listeners.props).forEach(function (propName) { | ||
var prop = instance.props[propName]; | ||
if (!prevProps || prevProps[propName] !== prop) { | ||
listeners.props[propName].forEach(function (l) { return l.next(prop); }); | ||
} | ||
}); | ||
listeners.allProps.forEach(function (l) { return l.next(instance.props); }); | ||
}; | ||
instance.reDecorateProps = function (nextProps) { | ||
@@ -232,10 +254,12 @@ Object.keys(nextProps).forEach(function (propName) { | ||
}; | ||
instance.pushProps = function (prevProps) { | ||
sendNext(prevProps); | ||
instance.pushProps = function (props) { | ||
listeners.forEach(function (listener) { | ||
listener.next(createPropsData(props)); | ||
}); | ||
}; | ||
instance.triggerMount = function () { | ||
listeners.mount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(MOUNT_EVENT)(undefined); | ||
}; | ||
instance.triggerUnmount = function () { | ||
listeners.unmount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(UNMOUNT_EVENT)(undefined); | ||
sinkSubscription.unsubscribe(); | ||
@@ -245,15 +269,15 @@ }; | ||
var state = instance.state; | ||
var stateProps = __assign({}, state.props, state.decoratedProps); | ||
var stateProps = state.props; | ||
if (state.replace === true) { | ||
return __assign({}, stateProps, { pushEvent: pushEvent }); | ||
} | ||
var componentProps = __assign({}, instance.props, decoratedProps, { pushEvent: pushEvent }); | ||
var additionalProps = __assign({}, decoratedProps, { pushEvent: pushEvent }); | ||
if (state.replace === false) { | ||
return __assign({}, componentProps, stateProps); | ||
return __assign({}, instance.props, stateProps, additionalProps); | ||
} | ||
return componentProps; | ||
return __assign({}, instance.props, additionalProps); | ||
}; | ||
instance.havePropsChanged = function (newProps, newState) { | ||
var state = instance.state; | ||
if (state.children || newState.children) { | ||
if (state.renderEffect) { | ||
return state.children !== newState.children; | ||
@@ -271,2 +295,3 @@ } | ||
}; | ||
var _a; | ||
}; }; | ||
@@ -297,2 +322,3 @@ | ||
this.reDecorateProps(nextProps); | ||
this.pushProps(nextProps); | ||
}; | ||
@@ -302,5 +328,2 @@ WithEffects.prototype.shouldComponentUpdate = function (nextProps, nextState) { | ||
}; | ||
WithEffects.prototype.componentDidUpdate = function (prevProps) { | ||
this.pushProps(prevProps); | ||
}; | ||
WithEffects.prototype.componentWillUnmount = function () { | ||
@@ -307,0 +330,0 @@ this.unmounted = true; |
235
index.js
@@ -8,2 +8,4 @@ 'use strict'; | ||
var xs = _interopDefault(require('xstream')); | ||
var dropRepeats = _interopDefault(require('xstream/extra/dropRepeats')); | ||
var $$observable = _interopDefault(require('symbol-observable')); | ||
var React = require('react'); | ||
@@ -61,2 +63,43 @@ | ||
var MOUNT_EVENT = '@@refract/event/mount'; | ||
var UNMOUNT_EVENT = '@@refract/event/unmount'; | ||
var DataType; | ||
(function (DataType) { | ||
DataType["EVENT"] = "event"; | ||
DataType["PROPS"] = "props"; | ||
DataType["CALLBACK"] = "callback"; | ||
})(DataType || (DataType = {})); | ||
var isEvent = function (eventName) { return function (data, index) { | ||
return data.type === DataType.EVENT && | ||
data.payload.name === eventName; | ||
}; }; | ||
var isProps = function (data) { return data.type === DataType.PROPS; }; | ||
var isCallback = function (propName) { return function (data) { | ||
return data.type === DataType.CALLBACK && | ||
data.payload.name === propName; | ||
}; }; | ||
var createEventData = function (name, value) { return ({ | ||
type: DataType.EVENT, | ||
payload: { | ||
name: name, | ||
value: value | ||
} | ||
}); }; | ||
var createPropsData = function (props) { return ({ | ||
type: DataType.PROPS, | ||
payload: props | ||
}); }; | ||
var createCallbackData = function (name, args) { return ({ | ||
type: DataType.CALLBACK, | ||
payload: { | ||
name: name, | ||
args: args | ||
} | ||
}); }; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var subscribeToSink = function (sink, next, error) { | ||
@@ -69,19 +112,48 @@ return sink.subscribe({ | ||
}; | ||
var createObservable = function (subscribe) { | ||
var unsubscribe; | ||
return xs.create({ | ||
start: function (listener) { | ||
unsubscribe = subscribe(listener); | ||
var createComponent = function (instance, dataObservable, pushEvent) { | ||
var data = function () { return xs.from(dataObservable); }; | ||
return { | ||
mount: data() | ||
.filter(isEvent(MOUNT_EVENT)) | ||
.mapTo(undefined), | ||
unmount: data() | ||
.filter(isEvent(UNMOUNT_EVENT)) | ||
.mapTo(undefined), | ||
observe: function (propName, valueTransformer) { | ||
if (propName && typeof instance.props[propName] === 'function') { | ||
return data() | ||
.filter(isCallback(propName)) | ||
.map(function (data) { | ||
var args = data.payload.args; | ||
return valueTransformer | ||
? valueTransformer(args) | ||
: args[0]; | ||
}); | ||
} | ||
if (propName) { | ||
return data() | ||
.filter(isProps) | ||
.map(function (data) { | ||
var prop = data.payload[propName]; | ||
return valueTransformer ? valueTransformer(prop) : prop; | ||
}) | ||
.compose(dropRepeats()); | ||
} | ||
return data() | ||
.filter(isProps) | ||
.map(function (data) { return data.payload; }) | ||
.compose(dropRepeats(shallowEquals)); | ||
}, | ||
stop: function () { | ||
unsubscribe(); | ||
} | ||
}); | ||
fromEvent: function (eventName, valueTransformer) { | ||
return data() | ||
.filter(isEvent(eventName)) | ||
.map(function (data) { | ||
var value = data.payload.value; | ||
return valueTransformer ? valueTransformer(value) : value; | ||
}); | ||
}, | ||
pushEvent: pushEvent | ||
}; | ||
}; | ||
var shallowEquals = function (left, right) { | ||
return left === right || | ||
(Object.keys(left).length === Object.keys(right).length && | ||
Object.keys(left).every(function (leftKey) { return left[leftKey] === right[leftKey]; })); | ||
}; | ||
var configureComponent = function (handler, errorHandler) { return function (aperture, instance, isValidElement, isComponentClass) { | ||
@@ -91,5 +163,5 @@ if (isValidElement === void 0) { isValidElement = function () { return false; }; } | ||
instance.state = { | ||
renderEffect: false, | ||
children: null, | ||
props: {}, | ||
decoratedProps: {} | ||
props: {} | ||
}; | ||
@@ -104,3 +176,3 @@ var setState = function (state) { | ||
else { | ||
instance.state = state; | ||
instance.state = __assign({}, instance.state, state); | ||
} | ||
@@ -113,2 +185,3 @@ }; | ||
setState({ | ||
renderEffect: true, | ||
children: effect | ||
@@ -118,15 +191,6 @@ }); | ||
else if (effect && effect.type === PROPS_EFFECT) { | ||
var payload_1 = effect.payload; | ||
var payload = effect.payload; | ||
setState({ | ||
replace: payload_1.replace, | ||
props: payload_1.props, | ||
decoratedProps: Object.keys(payload_1.props || {}).reduce(function (props, propName) { | ||
var prop = payload_1.props[propName]; | ||
var previousProp = instance.state.props[propName]; | ||
if (typeof prop === 'function' && | ||
prop !== previousProp) { | ||
decorateProp(props, prop, propName); | ||
} | ||
return props; | ||
}, {}) | ||
replace: payload.replace, | ||
props: payload.props | ||
}); | ||
@@ -139,14 +203,13 @@ } | ||
}; | ||
var listeners = { | ||
mount: [], | ||
unmount: [], | ||
allProps: [], | ||
props: {}, | ||
fnProps: {}, | ||
event: {} | ||
var decoratedProps = {}; | ||
var listeners = []; | ||
var addListener = function (listener) { | ||
listeners = listeners.concat(listener); | ||
}; | ||
var decoratedProps = {}; | ||
var removeListener = function (listener) { | ||
listeners = listeners.filter(function (l) { return l !== listener; }); | ||
}; | ||
var pushEvent = function (eventName) { return function (val) { | ||
(listeners.event[eventName] || []).forEach(function (listener) { | ||
return listener.next(val); | ||
listeners.forEach(function (listener) { | ||
listener.next(createEventData(eventName, val)); | ||
}); | ||
@@ -163,3 +226,5 @@ }; }; | ||
} | ||
(listeners.fnProps[propName] || []).forEach(function (l) { return l.next(args[0]); }); | ||
listeners.forEach(function (listener) { | ||
listener.next(createCallbackData(propName, args)); | ||
}); | ||
return prop.apply(void 0, args); | ||
@@ -173,59 +238,16 @@ }; | ||
}); | ||
var mountObservable = createObservable(function (listener) { | ||
listeners.mount = listeners.mount.concat(listener); | ||
return function () { return listeners.mount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var unmountObservable = createObservable(function (listener) { | ||
listeners.unmount = listeners.unmount.concat(listener); | ||
return function () { return listeners.unmount.filter(function (l) { return l !== listener; }); }; | ||
}); | ||
var createPropObservable = function (propName) { | ||
var listenerType = propName | ||
? typeof instance.props[propName] === 'function' | ||
? 'fnProps' | ||
: 'props' | ||
: 'allProps'; | ||
return createObservable(function (listener) { | ||
if (listenerType === 'allProps') { | ||
listener.next(instance.props); | ||
listeners.allProps = listeners.allProps.concat(listener); | ||
return function () { | ||
listeners.allProps.filter(function (l) { return l !== listener; }); | ||
}; | ||
var dataObservable = (_a = { | ||
subscribe: function (listener) { | ||
addListener(listener); | ||
listener.next(createPropsData(instance.props)); | ||
return { unsubscribe: function () { return removeListener(listener); } }; | ||
} | ||
if (listenerType === 'props') { | ||
listener.next(instance.props[propName]); | ||
} | ||
listeners[listenerType][propName] = (listeners[listenerType][propName] || []).concat(listener); | ||
return function () { | ||
listeners[listenerType][propName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var createEventObservable = function (eventName) { | ||
return createObservable(function (listener) { | ||
listeners.event[eventName] = (listeners.event[eventName] || []).concat(listener); | ||
return function () { | ||
listeners.event[eventName].filter(function (l) { return l !== listener; }); | ||
}; | ||
}); | ||
}; | ||
var component = { | ||
mount: mountObservable, | ||
unmount: unmountObservable, | ||
observe: createPropObservable, | ||
event: createEventObservable, | ||
pushEvent: pushEvent | ||
}; | ||
}, | ||
_a[$$observable] = function () { | ||
return this; | ||
}, | ||
_a); | ||
var component = createComponent(instance, dataObservable, pushEvent); | ||
var sinkObservable = aperture(instance.props)(component); | ||
var sinkSubscription = subscribeToSink(sinkObservable, finalHandler(instance.props), errorHandler ? errorHandler(instance.props) : undefined); | ||
var sendNext = function (prevProps) { | ||
Object.keys(listeners.props).forEach(function (propName) { | ||
var prop = instance.props[propName]; | ||
if (!prevProps || prevProps[propName] !== prop) { | ||
listeners.props[propName].forEach(function (l) { return l.next(prop); }); | ||
} | ||
}); | ||
listeners.allProps.forEach(function (l) { return l.next(instance.props); }); | ||
}; | ||
instance.reDecorateProps = function (nextProps) { | ||
@@ -239,10 +261,12 @@ Object.keys(nextProps).forEach(function (propName) { | ||
}; | ||
instance.pushProps = function (prevProps) { | ||
sendNext(prevProps); | ||
instance.pushProps = function (props) { | ||
listeners.forEach(function (listener) { | ||
listener.next(createPropsData(props)); | ||
}); | ||
}; | ||
instance.triggerMount = function () { | ||
listeners.mount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(MOUNT_EVENT)(undefined); | ||
}; | ||
instance.triggerUnmount = function () { | ||
listeners.unmount.forEach(function (l) { return l.next(undefined); }); | ||
pushEvent(UNMOUNT_EVENT)(undefined); | ||
sinkSubscription.unsubscribe(); | ||
@@ -252,15 +276,15 @@ }; | ||
var state = instance.state; | ||
var stateProps = __assign({}, state.props, state.decoratedProps); | ||
var stateProps = state.props; | ||
if (state.replace === true) { | ||
return __assign({}, stateProps, { pushEvent: pushEvent }); | ||
} | ||
var componentProps = __assign({}, instance.props, decoratedProps, { pushEvent: pushEvent }); | ||
var additionalProps = __assign({}, decoratedProps, { pushEvent: pushEvent }); | ||
if (state.replace === false) { | ||
return __assign({}, componentProps, stateProps); | ||
return __assign({}, instance.props, stateProps, additionalProps); | ||
} | ||
return componentProps; | ||
return __assign({}, instance.props, additionalProps); | ||
}; | ||
instance.havePropsChanged = function (newProps, newState) { | ||
var state = instance.state; | ||
if (state.children || newState.children) { | ||
if (state.renderEffect) { | ||
return state.children !== newState.children; | ||
@@ -278,2 +302,3 @@ } | ||
}; | ||
var _a; | ||
}; }; | ||
@@ -304,2 +329,3 @@ | ||
this.reDecorateProps(nextProps); | ||
this.pushProps(nextProps); | ||
}; | ||
@@ -309,5 +335,2 @@ WithEffects.prototype.shouldComponentUpdate = function (nextProps, nextState) { | ||
}; | ||
WithEffects.prototype.componentDidUpdate = function (prevProps) { | ||
this.pushProps(prevProps); | ||
}; | ||
WithEffects.prototype.componentWillUnmount = function () { | ||
@@ -314,0 +337,0 @@ this.unmounted = true; |
{ | ||
"name": "refract-xstream", | ||
"description": "Refract bindings for React with xstream: master your app effects reactively!", | ||
"version": "2.0.0-rc.3", | ||
"description": "Refract bindings for React with xstream: harness the power of reactive programming to supercharge your components!", | ||
"version": "2.0.0", | ||
"main": "index.js", | ||
@@ -30,3 +30,6 @@ "jsnext:main": "index.es.js", | ||
}, | ||
"homepage": "https://refract.js.org" | ||
"homepage": "https://refract.js.org", | ||
"dependencies": { | ||
"symbol-observable": "~1.2.0" | ||
} | ||
} |
@@ -6,4 +6,4 @@ <p align="center"> | ||
<p align="center"> | ||
Master your component's effects through the<br/> | ||
power of reactive programming. | ||
Harness the power of reactive programming<br/> | ||
to supercharge your components | ||
</p> | ||
@@ -31,6 +31,20 @@ <br/> | ||
Refract lets you isolate your app's side effects - API calls, analytics, logging, etc - so that you can write your code in a clear, pure, and declarative fashion by using reactive programming. | ||
* :bowling: **Decentralised**: attach effects and side-effects to your components, for better code splitting results | ||
* :sunrise: **Gradual**: use on an existing component today, throughout your app tomorrow | ||
* :rocket: **Reactive**: leverage the power and benefits of reactive programming | ||
* :floppy_disk: **Tiny**: less than 2Kb minified and gzipped | ||
* :pencil: **Typed**: written in TypeScript, fully typed integrations | ||
* :zap: **Universal**: supports React, React Native, Inferno and Preact | ||
Refract is an extensible library built for React, with bindings available for Inferno and Preact. In addition we provide a Redux integration, which can also serve as a template for integrations with other libraries. | ||
Refract lets you handle your component effects and side-effects, so that you can write your code in a clear, pure, and declarative fashion by using reactive programming. | ||
Refract makes reactive programming possible in React, React Native, Preact and Inferno, with only a single higher-order component! You can choose to start using a tiny bit of reactive programming, or go full reactive. Refract allows you to: | ||
* [Manage side effects](https://refract.js.org/) like API calls, analytics, logging, etc. | ||
* [Manipulate, replace and inject props](https://refract.js.org/usage/pushing-props), you can even [fully replace Redux `connect` HoC](https://refract.js.org/recipes/replace-connect) | ||
* [Handle state](https://refract.js.org/recipes/handling-state) | ||
* [Render components](https://refract.js.org/usage/rendering-components) | ||
We also provide a Redux integration, which can serve as a template for integrations with other libraries. With a single HoC, you can fully replace libraries like [recompose](https://github.com/acdlite/recompose), [redux-observable](https://redux-observable.js.org/), and [react-redux](https://github.com/reduxjs/react-redux) to name a few! | ||
# Why? | ||
@@ -40,8 +54,6 @@ | ||
However, our apps don't exist in a vacuum! They need to make network requests, handle data persistence, log analytics, deal with changing time, and so on. Any non-trivial app has to handle any number of these external effects. | ||
However, our apps don't exist in a vacuum! They need to handle state, make network requests, handle data persistence, log analytics, deal with changing time, and so on. Any non-trivial app has to handle any number of these effects. Wouldn't it be nice to cleanly separate them from our apps? | ||
These side-effects hold us back from writing fully declarative code. Wouldn't it be nice to cleanly separate them from our apps? | ||
Refract solves this problem for you, by harnessing the power of reactive programming. [For an in-depth introduction, head to `Why Refract`.](./docs/introduction/why-refract.md) | ||
Refract solves this problem for you. [For an in-depth introduction, head to `Why Refract`.](../../docs/introduction/why-refract.md) | ||
# Installation | ||
@@ -48,0 +60,0 @@ |
@@ -1,15 +0,3 @@ | ||
import { Listener } from './observable' | ||
export interface KeyedListeners { | ||
[key: string]: Array<Partial<Listener<any>>> | ||
} | ||
export interface Listeners { | ||
mount: Array<Partial<Listener<any>>> | ||
unmount: Array<Partial<Listener<any>>> | ||
allProps: Array<Partial<Listener<any>>> | ||
props: KeyedListeners | ||
fnProps: KeyedListeners | ||
event: KeyedListeners | ||
} | ||
export declare type Handler<P, E> = (intialProps: P) => (val: E) => void | ||
export declare type ErrorHandler<P> = (intialProps: P) => (error: any) => void | ||
export declare type PushEvent = (eventName: string) => <T>(val: T) => void |
import { withEffects } from './withEffects' | ||
import { ObservableComponent, Aperture } from './observable' | ||
import { ErrorHandler, Handler } from './baseTypes' | ||
import { ErrorHandler, Handler, PushEvent } from './baseTypes' | ||
import { compose, Compose } from './compose' | ||
@@ -12,2 +12,3 @@ import { asProps, toProps, PROPS_EFFECT, PropEffect } from './effects' | ||
ErrorHandler, | ||
PushEvent, | ||
compose, | ||
@@ -14,0 +15,0 @@ Compose, |
@@ -5,4 +5,10 @@ import { Stream, Listener, Subscription } from 'xstream' | ||
export interface ObservableComponent { | ||
observe: <T>(propName?: string) => Stream<T> | ||
event: <T>(eventName: string) => Stream<T> | ||
observe: <T>( | ||
propName?: string, | ||
valueTransformer?: (val: any) => T | ||
) => Stream<T> | ||
fromEvent: <T>( | ||
eventName: string, | ||
valueTransformer?: (val: any) => T | ||
) => Stream<T> | ||
mount: Stream<any> | ||
@@ -20,2 +26,6 @@ unmount: Stream<any> | ||
) => Subscription | ||
export declare const createObservable: <T>(subscribe: any) => Stream<T> | ||
export declare const createComponent: <P>( | ||
instance: any, | ||
dataObservable: any, | ||
pushEvent: any | ||
) => ObservableComponent |
@@ -8,3 +8,3 @@ /// <reference types="react" /> | ||
props: object | ||
decoratedProps: object | ||
renderEffect: boolean | ||
children: React.ReactNode | null | ||
@@ -11,0 +11,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
40860
12
857
0
167
3
+ Addedsymbol-observable@~1.2.0
+ Addedsymbol-observable@1.2.0(transitive)