constate
Advanced tools
Comparing version 0.1.2 to 0.2.0
@@ -56,20 +56,24 @@ 'use strict'; | ||
var mapStateToActions = function mapStateToActions(setState, actionsMap) { | ||
return Object.keys(actionsMap).reduce(function (finalActions, actionKey) { | ||
var mapWith = function mapWith(map, transform) { | ||
return Object.keys(map).reduce(function (final, key) { | ||
var _babelHelpers$extends; | ||
return _extends({}, finalActions, (_babelHelpers$extends = {}, _babelHelpers$extends[actionKey] = function () { | ||
return setState(actionsMap[actionKey].apply(actionsMap, arguments)); | ||
}, _babelHelpers$extends)); | ||
return _extends({}, final, (_babelHelpers$extends = {}, _babelHelpers$extends[key] = transform(map[key]), _babelHelpers$extends)); | ||
}, {}); | ||
}; | ||
var mapStateToSelectors = function mapStateToSelectors(state, selectorsMap) { | ||
return Object.keys(selectorsMap).reduce(function (finalSelectors, selectorKey) { | ||
var _babelHelpers$extends2; | ||
var mapSetStateToActions = function mapSetStateToActions(setState, actionsMap) { | ||
return mapWith(actionsMap, function (action) { | ||
return function () { | ||
return setState(action.apply(undefined, arguments)); | ||
}; | ||
}); | ||
}; | ||
return _extends({}, finalSelectors, (_babelHelpers$extends2 = {}, _babelHelpers$extends2[selectorKey] = function () { | ||
return selectorsMap[selectorKey].apply(selectorsMap, arguments)(state); | ||
}, _babelHelpers$extends2)); | ||
}, {}); | ||
var mapArgumentToFunctions = function mapArgumentToFunctions(argument, fnMap) { | ||
return mapWith(fnMap, function (fn) { | ||
return function () { | ||
return fn.apply(undefined, arguments)(argument); | ||
}; | ||
}); | ||
}; | ||
@@ -80,13 +84,14 @@ | ||
function ConsumerChild() { | ||
function ConsumerChild(props) { | ||
classCallCheck(this, ConsumerChild); | ||
return possibleConstructorReturn(this, _React$Component.apply(this, arguments)); | ||
} | ||
ConsumerChild.prototype.componentDidMount = function componentDidMount() { | ||
var _props = this.props, | ||
context = _props.context, | ||
initialState = _props.initialState, | ||
setState = _props.setState; | ||
var _this = possibleConstructorReturn(this, _React$Component.call(this, props)); | ||
_initialiseProps.call(_this); | ||
var _this$props = _this.props, | ||
context = _this$props.context, | ||
initialState = _this$props.initialState, | ||
setState = _this$props.setState; | ||
setState(function (state) { | ||
@@ -97,23 +102,17 @@ var _ref; | ||
}); | ||
}; | ||
return _this; | ||
} | ||
ConsumerChild.prototype.render = function render() { | ||
var _props2 = this.props, | ||
setState = _props2.setState, | ||
state = _props2.state, | ||
context = _props2.context, | ||
children = _props2.children; | ||
var _props = this.props, | ||
context = _props.context, | ||
children = _props.children, | ||
actions = _props.actions, | ||
selectors = _props.selectors, | ||
effects = _props.effects; | ||
var state = this.props.state[context] || {}; | ||
var effectsArg = { state: state, setState: this.handleSetState }; | ||
var actions = this.props.actions && mapStateToActions(function (fn) { | ||
return setState(function (s) { | ||
var _ref2; | ||
return _ref2 = {}, _ref2[context] = _extends({}, s[context], fn(s[context])), _ref2; | ||
}); | ||
}, this.props.actions); | ||
var selectors = this.props.selectors && mapStateToSelectors(state[context] || {}, this.props.selectors); | ||
return children(_extends({}, state[context], actions, selectors)); | ||
return children(_extends({}, state, actions && mapSetStateToActions(this.handleSetState, actions), selectors && mapArgumentToFunctions(state, selectors), effects && mapArgumentToFunctions(effectsArg, effects))); | ||
}; | ||
@@ -130,2 +129,3 @@ | ||
selectors: PropTypes.objectOf(PropTypes.func), | ||
effects: PropTypes.objectOf(PropTypes.func), | ||
children: PropTypes.func.isRequired, | ||
@@ -135,3 +135,18 @@ context: PropTypes.string | ||
var _initialiseProps = function _initialiseProps() { | ||
var _this2 = this; | ||
this.handleSetState = function (fn) { | ||
var _props2 = _this2.props, | ||
setState = _props2.setState, | ||
context = _props2.context; | ||
return setState(function (state) { | ||
var _ref2; | ||
return _ref2 = {}, _ref2[context] = _extends({}, state[context], fn(state[context])), _ref2; | ||
}); | ||
}; | ||
}; | ||
var Consumer = function Consumer(props) { | ||
@@ -149,8 +164,2 @@ return React.createElement( | ||
/** | ||
* @class Provider | ||
* @prop {React.Node} children | ||
* @prop {Object=} initialState | ||
*/ | ||
var Provider = function (_React$Component) { | ||
@@ -168,3 +177,3 @@ inherits(Provider, _React$Component); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.changeState = function (fn) { | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.handleSetState = function (fn) { | ||
_this.setState(function (state) { | ||
@@ -177,3 +186,3 @@ return { | ||
state: _this.props.initialState, | ||
setState: _this.changeState | ||
setState: _this.handleSetState | ||
}, _temp), possibleConstructorReturn(_this, _ret); | ||
@@ -201,11 +210,2 @@ } | ||
/** | ||
* @class State | ||
* @prop {Function} children | ||
* @prop {Object=} initialState | ||
* @prop {Object=} actions | ||
* @prop {Object=} selectors | ||
* @prop {String=} context | ||
*/ | ||
var State = function (_React$Component) { | ||
@@ -223,3 +223,3 @@ inherits(State, _React$Component); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), possibleConstructorReturn(_this, _ret); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _initialiseProps$1.call(_this), _temp), possibleConstructorReturn(_this, _ret); | ||
} | ||
@@ -235,6 +235,8 @@ | ||
actions = _props.actions, | ||
selectors = _props.selectors; | ||
selectors = _props.selectors, | ||
effects = _props.effects; | ||
var effectsArg = { state: this.state, setState: this.handleSetState }; | ||
return children(_extends({}, this.state, actions && mapStateToActions(this.changeState, actions), selectors && mapStateToSelectors(this.state, selectors))); | ||
return children(_extends({}, this.state, actions && mapSetStateToActions(this.handleSetState, actions), selectors && mapArgumentToFunctions(this.state, selectors), effects && mapArgumentToFunctions(effectsArg, effects))); | ||
}; | ||
@@ -250,2 +252,3 @@ | ||
selectors: PropTypes.objectOf(PropTypes.func), | ||
effects: PropTypes.objectOf(PropTypes.func), | ||
context: PropTypes.string | ||
@@ -257,3 +260,3 @@ }; | ||
var _initialiseProps = function _initialiseProps() { | ||
var _initialiseProps$1 = function _initialiseProps() { | ||
var _this2 = this; | ||
@@ -263,3 +266,3 @@ | ||
this.changeState = function () { | ||
this.handleSetState = function () { | ||
return _this2.setState.apply(_this2, arguments); | ||
@@ -266,0 +269,0 @@ }; |
@@ -50,20 +50,24 @@ import React from 'react'; | ||
var mapStateToActions = function mapStateToActions(setState, actionsMap) { | ||
return Object.keys(actionsMap).reduce(function (finalActions, actionKey) { | ||
var mapWith = function mapWith(map, transform) { | ||
return Object.keys(map).reduce(function (final, key) { | ||
var _babelHelpers$extends; | ||
return _extends({}, finalActions, (_babelHelpers$extends = {}, _babelHelpers$extends[actionKey] = function () { | ||
return setState(actionsMap[actionKey].apply(actionsMap, arguments)); | ||
}, _babelHelpers$extends)); | ||
return _extends({}, final, (_babelHelpers$extends = {}, _babelHelpers$extends[key] = transform(map[key]), _babelHelpers$extends)); | ||
}, {}); | ||
}; | ||
var mapStateToSelectors = function mapStateToSelectors(state, selectorsMap) { | ||
return Object.keys(selectorsMap).reduce(function (finalSelectors, selectorKey) { | ||
var _babelHelpers$extends2; | ||
var mapSetStateToActions = function mapSetStateToActions(setState, actionsMap) { | ||
return mapWith(actionsMap, function (action) { | ||
return function () { | ||
return setState(action.apply(undefined, arguments)); | ||
}; | ||
}); | ||
}; | ||
return _extends({}, finalSelectors, (_babelHelpers$extends2 = {}, _babelHelpers$extends2[selectorKey] = function () { | ||
return selectorsMap[selectorKey].apply(selectorsMap, arguments)(state); | ||
}, _babelHelpers$extends2)); | ||
}, {}); | ||
var mapArgumentToFunctions = function mapArgumentToFunctions(argument, fnMap) { | ||
return mapWith(fnMap, function (fn) { | ||
return function () { | ||
return fn.apply(undefined, arguments)(argument); | ||
}; | ||
}); | ||
}; | ||
@@ -74,13 +78,14 @@ | ||
function ConsumerChild() { | ||
function ConsumerChild(props) { | ||
classCallCheck(this, ConsumerChild); | ||
return possibleConstructorReturn(this, _React$Component.apply(this, arguments)); | ||
} | ||
ConsumerChild.prototype.componentDidMount = function componentDidMount() { | ||
var _props = this.props, | ||
context = _props.context, | ||
initialState = _props.initialState, | ||
setState = _props.setState; | ||
var _this = possibleConstructorReturn(this, _React$Component.call(this, props)); | ||
_initialiseProps.call(_this); | ||
var _this$props = _this.props, | ||
context = _this$props.context, | ||
initialState = _this$props.initialState, | ||
setState = _this$props.setState; | ||
setState(function (state) { | ||
@@ -91,23 +96,17 @@ var _ref; | ||
}); | ||
}; | ||
return _this; | ||
} | ||
ConsumerChild.prototype.render = function render() { | ||
var _props2 = this.props, | ||
setState = _props2.setState, | ||
state = _props2.state, | ||
context = _props2.context, | ||
children = _props2.children; | ||
var _props = this.props, | ||
context = _props.context, | ||
children = _props.children, | ||
actions = _props.actions, | ||
selectors = _props.selectors, | ||
effects = _props.effects; | ||
var state = this.props.state[context] || {}; | ||
var effectsArg = { state: state, setState: this.handleSetState }; | ||
var actions = this.props.actions && mapStateToActions(function (fn) { | ||
return setState(function (s) { | ||
var _ref2; | ||
return _ref2 = {}, _ref2[context] = _extends({}, s[context], fn(s[context])), _ref2; | ||
}); | ||
}, this.props.actions); | ||
var selectors = this.props.selectors && mapStateToSelectors(state[context] || {}, this.props.selectors); | ||
return children(_extends({}, state[context], actions, selectors)); | ||
return children(_extends({}, state, actions && mapSetStateToActions(this.handleSetState, actions), selectors && mapArgumentToFunctions(state, selectors), effects && mapArgumentToFunctions(effectsArg, effects))); | ||
}; | ||
@@ -124,2 +123,3 @@ | ||
selectors: PropTypes.objectOf(PropTypes.func), | ||
effects: PropTypes.objectOf(PropTypes.func), | ||
children: PropTypes.func.isRequired, | ||
@@ -129,3 +129,18 @@ context: PropTypes.string | ||
var _initialiseProps = function _initialiseProps() { | ||
var _this2 = this; | ||
this.handleSetState = function (fn) { | ||
var _props2 = _this2.props, | ||
setState = _props2.setState, | ||
context = _props2.context; | ||
return setState(function (state) { | ||
var _ref2; | ||
return _ref2 = {}, _ref2[context] = _extends({}, state[context], fn(state[context])), _ref2; | ||
}); | ||
}; | ||
}; | ||
var Consumer = function Consumer(props) { | ||
@@ -143,8 +158,2 @@ return React.createElement( | ||
/** | ||
* @class Provider | ||
* @prop {React.Node} children | ||
* @prop {Object=} initialState | ||
*/ | ||
var Provider = function (_React$Component) { | ||
@@ -162,3 +171,3 @@ inherits(Provider, _React$Component); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.changeState = function (fn) { | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.handleSetState = function (fn) { | ||
_this.setState(function (state) { | ||
@@ -171,3 +180,3 @@ return { | ||
state: _this.props.initialState, | ||
setState: _this.changeState | ||
setState: _this.handleSetState | ||
}, _temp), possibleConstructorReturn(_this, _ret); | ||
@@ -195,11 +204,2 @@ } | ||
/** | ||
* @class State | ||
* @prop {Function} children | ||
* @prop {Object=} initialState | ||
* @prop {Object=} actions | ||
* @prop {Object=} selectors | ||
* @prop {String=} context | ||
*/ | ||
var State = function (_React$Component) { | ||
@@ -217,3 +217,3 @@ inherits(State, _React$Component); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), possibleConstructorReturn(_this, _ret); | ||
return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _initialiseProps$1.call(_this), _temp), possibleConstructorReturn(_this, _ret); | ||
} | ||
@@ -229,6 +229,8 @@ | ||
actions = _props.actions, | ||
selectors = _props.selectors; | ||
selectors = _props.selectors, | ||
effects = _props.effects; | ||
var effectsArg = { state: this.state, setState: this.handleSetState }; | ||
return children(_extends({}, this.state, actions && mapStateToActions(this.changeState, actions), selectors && mapStateToSelectors(this.state, selectors))); | ||
return children(_extends({}, this.state, actions && mapSetStateToActions(this.handleSetState, actions), selectors && mapArgumentToFunctions(this.state, selectors), effects && mapArgumentToFunctions(effectsArg, effects))); | ||
}; | ||
@@ -244,2 +246,3 @@ | ||
selectors: PropTypes.objectOf(PropTypes.func), | ||
effects: PropTypes.objectOf(PropTypes.func), | ||
context: PropTypes.string | ||
@@ -251,3 +254,3 @@ }; | ||
var _initialiseProps = function _initialiseProps() { | ||
var _initialiseProps$1 = function _initialiseProps() { | ||
var _this2 = this; | ||
@@ -257,3 +260,3 @@ | ||
this.changeState = function () { | ||
this.handleSetState = function () { | ||
return _this2.setState.apply(_this2, arguments); | ||
@@ -260,0 +263,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("prop-types")):"function"==typeof define&&define.amd?define(["exports","react","prop-types"],e):e(t.constate={},t.React,t.PropTypes)}(this,function(t,e,n){"use strict";e=e&&e.hasOwnProperty("default")?e.default:e,n=n&&n.hasOwnProperty("default")?n.default:n;var r=e.createContext({}),o=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},i=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t},a=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},s=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},c=function(t,e){return Object.keys(e).reduce(function(n,r){var o;return i({},n,((o={})[r]=function(){return t(e[r].apply(e,arguments))},o))},{})},u=function(t,e){return Object.keys(e).reduce(function(n,r){var o;return i({},n,((o={})[r]=function(){return e[r].apply(e,arguments)(t)},o))},{})},p=function(t){function e(){return o(this,e),s(this,t.apply(this,arguments))}return a(e,t),e.prototype.componentDidMount=function(){var t=this.props,e=t.context,n=t.initialState;(0,t.setState)(function(t){var r;return(r={})[e]=i({},n,t[e]),r})},e.prototype.render=function(){var t=this.props,e=t.setState,n=t.state,r=t.context,o=t.children,a=this.props.actions&&c(function(t){return e(function(e){var n;return(n={})[r]=i({},e[r],t(e[r])),n})},this.props.actions),s=this.props.selectors&&u(n[r]||{},this.props.selectors);return o(i({},n[r],a,s))},e}(e.Component);p.propTypes={initialState:n.object,state:n.object.isRequired,setState:n.func.isRequired,actions:n.objectOf(n.func),selectors:n.objectOf(n.func),children:n.func.isRequired,context:n.string};var f=function(t){return e.createElement(r.Consumer,null,function(n){return e.createElement(p,i({},n,t))})},l=function(t){function n(){var e,r;o(this,n);for(var a=arguments.length,c=Array(a),u=0;u<a;u++)c[u]=arguments[u];return e=r=s(this,t.call.apply(t,[this].concat(c))),r.changeState=function(t){r.setState(function(e){return{state:i({},e.state,t(e.state))}})},r.state={state:r.props.initialState,setState:r.changeState},s(r,e)}return a(n,t),n.prototype.render=function(){return e.createElement(r.Provider,{value:this.state},this.props.children)},n}(e.Component);l.propTypes={children:n.node,initialState:n.object},l.defaultProps={initialState:{}};var h=function(t){function n(){var e,r;o(this,n);for(var i=arguments.length,a=Array(i),c=0;c<i;c++)a[c]=arguments[c];return e=r=s(this,t.call.apply(t,[this].concat(a))),y.call(r),s(r,e)}return a(n,t),n.prototype.render=function(){if(this.props.context)return e.createElement(f,this.props);var t=this.props,n=t.children,r=t.actions,o=t.selectors;return n(i({},this.state,r&&c(this.changeState,r),o&&u(this.state,o)))},n}(e.Component);h.propTypes={children:n.func.isRequired,initialState:n.object,actions:n.objectOf(n.func),selectors:n.objectOf(n.func),context:n.string},h.defaultProps={initialState:{}};var y=function(){var t=this;this.state=this.props.initialState,this.changeState=function(){return t.setState.apply(t,arguments)}};t.Consumer=f,t.Context=r,t.Provider=l,t.State=h,Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("prop-types")):"function"==typeof define&&define.amd?define(["exports","react","prop-types"],e):e(t.constate={},t.React,t.PropTypes)}(this,function(t,e,n){"use strict";e=e&&e.hasOwnProperty("default")?e.default:e,n=n&&n.hasOwnProperty("default")?n.default:n;var r=e.createContext({}),o=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},i=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t},a=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},s=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},c=function(t,e){return Object.keys(t).reduce(function(n,r){var o;return i({},n,((o={})[r]=e(t[r]),o))},{})},u=function(t,e){return c(e,function(e){return function(){return t(e.apply(void 0,arguments))}})},f=function(t,e){return c(e,function(e){return function(){return e.apply(void 0,arguments)(t)}})},p=function(t){function e(n){o(this,e);var r=s(this,t.call(this,n));l.call(r);var a=r.props,c=a.context,u=a.initialState;return(0,a.setState)(function(t){var e;return(e={})[c]=i({},u,t[c]),e}),r}return a(e,t),e.prototype.render=function(){var t=this.props,e=t.context,n=t.children,r=t.actions,o=t.selectors,a=t.effects,s=this.props.state[e]||{},c={state:s,setState:this.handleSetState};return n(i({},s,r&&u(this.handleSetState,r),o&&f(s,o),a&&f(c,a)))},e}(e.Component);p.propTypes={initialState:n.object,state:n.object.isRequired,setState:n.func.isRequired,actions:n.objectOf(n.func),selectors:n.objectOf(n.func),effects:n.objectOf(n.func),children:n.func.isRequired,context:n.string};var l=function(){var t=this;this.handleSetState=function(e){var n=t.props,r=n.setState,o=n.context;return r(function(t){var n;return(n={})[o]=i({},t[o],e(t[o])),n})}},h=function(t){return e.createElement(r.Consumer,null,function(n){return e.createElement(p,i({},n,t))})},d=function(t){function n(){var e,r;o(this,n);for(var a=arguments.length,c=Array(a),u=0;u<a;u++)c[u]=arguments[u];return e=r=s(this,t.call.apply(t,[this].concat(c))),r.handleSetState=function(t){r.setState(function(e){return{state:i({},e.state,t(e.state))}})},r.state={state:r.props.initialState,setState:r.handleSetState},s(r,e)}return a(n,t),n.prototype.render=function(){return e.createElement(r.Provider,{value:this.state},this.props.children)},n}(e.Component);d.propTypes={children:n.node,initialState:n.object},d.defaultProps={initialState:{}};var y=function(t){function n(){var e,r;o(this,n);for(var i=arguments.length,a=Array(i),c=0;c<i;c++)a[c]=arguments[c];return e=r=s(this,t.call.apply(t,[this].concat(a))),S.call(r),s(r,e)}return a(n,t),n.prototype.render=function(){if(this.props.context)return e.createElement(h,this.props);var t=this.props,n=t.children,r=t.actions,o=t.selectors,a=t.effects,s={state:this.state,setState:this.handleSetState};return n(i({},this.state,r&&u(this.handleSetState,r),o&&f(this.state,o),a&&f(s,a)))},n}(e.Component);y.propTypes={children:n.func.isRequired,initialState:n.object,actions:n.objectOf(n.func),selectors:n.objectOf(n.func),effects:n.objectOf(n.func),context:n.string},y.defaultProps={initialState:{}};var S=function(){var t=this;this.state=this.props.initialState,this.handleSetState=function(){return t.setState.apply(t,arguments)}};t.Consumer=h,t.Context=r,t.Provider=d,t.State=y,Object.defineProperty(t,"__esModule",{value:!0})}); |
{ | ||
"name": "constate", | ||
"version": "0.1.2", | ||
"version": "0.2.0", | ||
"description": "Yet another React state management library that lets you work with local state and scale up to global state with ease", | ||
@@ -28,4 +28,3 @@ "license": "MIT", | ||
"clean": "rimraf dist", | ||
"docs": "documentation readme src --section API --markdown-toc false", | ||
"prebuild": "npm run clean && yarn docs", | ||
"prebuild": "npm run clean", | ||
"build": "rollup -c", | ||
@@ -71,3 +70,2 @@ "watch": "npm-watch", | ||
"babel-preset-stage-1": "^6.24.1", | ||
"documentation": "^6.1.0", | ||
"enzyme": "^3.3.0", | ||
@@ -74,0 +72,0 @@ "enzyme-adapter-react-16": "^1.1.1", |
229
README.md
@@ -16,14 +16,47 @@ <p align="center"> | ||
~2KB React state management library that lets you work with local state and scale up to global state with ease when needed. | ||
~2kB React state management library that lets you work with [local state](#local-state) and scale up to [global state](#global-state) with ease when needed. | ||
Demo: <https://codesandbox.io/s/7p2qv6mmq> | ||
👓 [**Read the introductory article**](https://medium.freecodecamp.org/reacts-new-context-api-how-to-toggle-between-local-and-global-state-c6ace81443d0)<br> | ||
🎮 [**Play with the demo**](https://codesandbox.io/s/7p2qv6mmq) | ||
## Install | ||
<br> | ||
<hr> | ||
<p align="center"> | ||
If you find this useful, please don't forget to star ⭐️ the repo, as this will help to promote the project.<br> | ||
Follow me on <a href="https://twitter.com/diegohaz">Twitter</a> and <a href="https://github.com/diegohaz">GitHub</a> to keep updated about this project and <a href="https://github.com/diegohaz?tab=repositories">others</a>. | ||
</p> | ||
<hr> | ||
<br> | ||
## Install 📦 | ||
```sh | ||
npm i -S constate | ||
npm i constate | ||
``` | ||
## Usage | ||
## Quick start 💥 | ||
```jsx | ||
import React from "react"; | ||
import { State } from "constate"; | ||
const initialState = { count: 0 }; | ||
const actions = { | ||
increment: () => state => ({ count: state.count + 1 }) | ||
}; | ||
const Counter = () => ( | ||
<State initialState={initialState} actions={actions}> | ||
{({ count, increment }) => ( | ||
<button onClick={increment}>{count}</button> | ||
)} | ||
</State> | ||
); | ||
``` | ||
<p align="center"><img src="https://user-images.githubusercontent.com/3068563/38770201-59f82fec-3fe5-11e8-9cd0-4dacf3d12f27.gif" alt="Example"></p> | ||
## Guide 📖 | ||
**Table of Contents** | ||
@@ -34,3 +67,7 @@ | ||
- [Composing state](#composing-state) | ||
- [Effects](#effects) | ||
- [Global initial state](#global-initial-state) | ||
- [State in lifecycle methods](#state-in-lifecycle-methods) | ||
- [Call selectors in actions](#call-selectors-in-actions) | ||
- [Call actions in effects](#call-actions-in-effects) | ||
- [Testing](#testing) | ||
@@ -61,3 +98,3 @@ | ||
initialState={initialState} | ||
actions={actiosn} | ||
actions={actions} | ||
selectors={selectors} | ||
@@ -85,2 +122,4 @@ {...props} | ||
<p align="center"><img src="https://user-images.githubusercontent.com/3068563/38770128-2d92da2a-3fe4-11e8-858f-b5cba87ce686.gif" alt="Example"></p> | ||
### Global state | ||
@@ -92,3 +131,3 @@ | ||
const CounterButton = () => ( | ||
<CounterState context="foo"> | ||
<CounterState context="counter1"> | ||
{({ increment }) => <button onClick={() => increment(1)}>Increment</button>} | ||
@@ -99,3 +138,3 @@ </CounterState> | ||
const CounterValue = () => ( | ||
<CounterState context="foo"> | ||
<CounterState context="counter1"> | ||
{({ count }) => <div>{count}</div>} | ||
@@ -113,2 +152,4 @@ </CounterState> | ||
<p align="center"><img src="https://user-images.githubusercontent.com/3068563/38770261-8b108952-3fe6-11e8-98c9-c181d0d8b51e.gif" alt="Example"></p> | ||
### Composing state | ||
@@ -144,3 +185,5 @@ | ||
<CounterState initialState={initialState} actions={actions}> | ||
{({ decrement }) => <button onClick={() => decrement(1)}>Decrement</button>} | ||
{({ count, decrement }) => ( | ||
<button onClick={() => decrement(1)}>{count}</button> | ||
)} | ||
</CounterState> | ||
@@ -150,4 +193,30 @@ ); | ||
<p align="center"><img src="https://user-images.githubusercontent.com/3068563/38770260-8ad70bb4-3fe6-11e8-91a6-1589be04ed9e.gif" alt="Example"></p> | ||
Those new members will work even if you use `context`. | ||
### Effects | ||
An effect is a method that receives both `state` and `setState`. This is useful if you need to perform side effects, like `async` actions, or just want to use `setState`. | ||
```jsx | ||
export const effects = { | ||
tick: () => ({ setState }) => { | ||
setTimeout(() => { | ||
setState(state => ({ count: state.count + 1 })); | ||
effects.tick()({ setState }) | ||
}, 1000); | ||
} | ||
}; | ||
const AutomaticCounterButton = () => ( | ||
<CounterState effects={effects}> | ||
{({ count, tick }) => ( | ||
<button onClick={tick}>{count}</button> | ||
)} | ||
</CounterState> | ||
); | ||
``` | ||
### Global initial state | ||
@@ -159,3 +228,3 @@ | ||
const initialState = { | ||
foo: { | ||
counter1: { | ||
count: 10 | ||
@@ -172,6 +241,78 @@ } | ||
This way, all `State` with `context="foo"` will start with `{ count: 10 }` | ||
This way, all `State` with `context="counter1"` will start with `{ count: 10 }` | ||
> Note: while using context, only the `initialState` of the first `State` in the tree will be considered. `Provider` will always take precedence over `State`. | ||
### State in lifecycle methods | ||
As stated in the [official docs](https://reactjs.org/docs/context.html#accessing-context-in-lifecycle-methods), to access state in lifecycle methods you can just pass the state down as a prop to another component and use it just like another prop: | ||
```jsx | ||
class CounterButton extends React.Component { | ||
componentDidMount() { | ||
this.props.state.increment(1); | ||
} | ||
render() { | ||
const { increment } = this.props.state; | ||
return <button onClick={() => increment(1)}>Increment</button>; | ||
} | ||
} | ||
export default props => ( | ||
<CounterState context="counter1"> | ||
{state => <CounterButton {...props} state={state} />} | ||
</CounterState> | ||
); | ||
``` | ||
Another alternative is to use <https://github.com/reactions/component>: | ||
```jsx | ||
import Component from "@reactions/component"; | ||
const CounterButton = () => ( | ||
<CounterState context="counter1"> | ||
{({ increment }) => ( | ||
<Component didMount={() => increment(1)}> | ||
<button onClick={() => increment(1)}>Increment</button> | ||
</Component> | ||
)} | ||
</CounterState> | ||
); | ||
``` | ||
### Call selectors in actions | ||
This is just JavaScript: | ||
```jsx | ||
export const selectors = { | ||
isEven: () => state => state.count % 2 === 0 | ||
}; | ||
export const actions = { | ||
increment: () => state => ({ | ||
count: state.count + (selectors.isEven()(state) ? 2 : 1) | ||
}) | ||
}; | ||
``` | ||
### Call actions in effects | ||
Aren't you already convinced that this is JavaScript? | ||
```jsx | ||
const increment = amount => state => ({ count: state.count + amount }) | ||
export const effects = { | ||
tick: amount => ({ setState }) => { | ||
setTimeout(() => { | ||
setState(increment(amount)); | ||
effects.tick(amount)({ setState }) | ||
}, 1000); | ||
} | ||
}; | ||
``` | ||
### Testing | ||
@@ -199,38 +340,64 @@ | ||
## API | ||
Testing `effects` can be a little tricky depending on how you implement them. This is how we can test our `tick` effect with [Jest](https://facebook.github.io/jest): | ||
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> | ||
```jsx | ||
import { effects } from "./CounterState"; | ||
### Provider | ||
test("tick", () => { | ||
jest.useFakeTimers(); | ||
**Properties** | ||
let state = { count: 0 }; | ||
const setState = fn => { | ||
state = fn(state); | ||
}; | ||
- `children` **React.Node** | ||
- `initialState` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** | ||
effects.tick()({ state, setState }); | ||
### State | ||
jest.advanceTimersByTime(1000); | ||
expect(state).toEqual({ count: 1 }); | ||
**Properties** | ||
jest.advanceTimersByTime(1000); | ||
expect(state).toEqual({ count: 2 }); | ||
}); | ||
``` | ||
- `children` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** | ||
- `initialState` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** | ||
- `actions` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** | ||
- `selectors` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** | ||
- `context` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** | ||
## API 🧐 | ||
## Contributing | ||
```js | ||
type Action = () => (state: Object) => Object; | ||
If you find some bug, please [create an issue](https://github.com/diegohaz/constate/issues/new) providing instructions to reproduce it. It's always very appreciable if you find the time to fix it. In this case, please [submit a PR](https://github.com/diegohaz/constate/pulls). | ||
type Selector = () => (state: Object) => any; | ||
If you're a beginner, it'll be a pleasure to help you contribute. See [the beginner's guide to contributing to a GitHub project](https://akrabat.com/the-beginners-guide-to-contributing-to-a-github-project/). | ||
type Effect = () => ({ state: Object, setState: Function }) => void; | ||
Make sure to install dependencies (`yarn` or `npm install`) and to lint and test the code before submitting the PR (`yarn lint && yarn test`). | ||
type StateProps = { | ||
children: (state: Object) => React.Node, | ||
initialState: Object, | ||
actions: { [string]: Action }, | ||
selectors: { [string]: Selector }, | ||
effects: { [string]: Effect }, | ||
context: string | ||
}; | ||
## TODO | ||
type ProviderProps = { | ||
children: React.Node, | ||
initialState: Object | ||
}; | ||
``` | ||
- Side effects / async actions ([#1](https://github.com/diegohaz/constate/issues/1)) | ||
## Contributing 👥 | ||
If you find a bug, please [create an issue](https://github.com/diegohaz/constate/issues/new) providing instructions to reproduce it. It's always very appreciable if you find the time to fix it. In this case, please [submit a PR](https://github.com/diegohaz/constate/pulls). | ||
If you're a beginner, it'll be a pleasure to help you contribute. You can start by reading [the beginner's guide to contributing to a GitHub project](https://akrabat.com/the-beginners-guide-to-contributing-to-a-github-project/). | ||
## TODO 📝 | ||
- Middlewares? ([create an issue](https://github.com/diegohaz/constate/issues/new) if you find a use case for this) | ||
- Debugger/devtools | ||
- Memoize selectors | ||
- Global actions/selectors | ||
## License | ||
## License ⚖️ | ||
MIT © [Diego Haz](https://github.com/diegohaz) |
33520
39
417
392