UNPKG

statty

Version:

A tiny and unobtrusive state management library for React and Preact apps

184 lines (153 loc) 5.31 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('prop-types')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'prop-types'], factory) : (factory((global.statty = {}),global.React,global.PropTypes)); }(this, (function (exports,react,PropTypes) { 'use strict'; PropTypes = PropTypes && PropTypes.hasOwnProperty('default') ? PropTypes['default'] : PropTypes; var isShallowEqual = function isShallowEqual (a, b) { if (a === b) { return true } for (var i in a) { if (!(i in b)) { return false } } for (var i in b) { if (a[i] !== b[i]) { return false } } return true }; var isObjectNotNull = function (a, b) { return ( typeof a === 'object' && typeof b === 'object' && a !== null && b !== null ) }; var State = (function (Component$$1) { function State (props, context) { Component$$1.call(this, props, context); this.broadcast = context.__statty__.broadcast; this.inspect = context.__statty__.inspect; this.state = props.state ? props.state : props.select(this.broadcast.getState()); this.update = this.update.bind(this); this.setStateIfNeeded = this.setStateIfNeeded.bind(this); } if ( Component$$1 ) State.__proto__ = Component$$1; State.prototype = Object.create( Component$$1 && Component$$1.prototype ); State.prototype.constructor = State; State.prototype.update = function update (updaterFn) { if (this.props.state) { this.setState(updaterFn); } else { var oldState = this.broadcast.getState(); var nextState = updaterFn(oldState); this.inspect && this.inspect(oldState, nextState, updaterFn); this.broadcast.setState(nextState); } }; State.prototype.setStateIfNeeded = function setStateIfNeeded (nextState) { var oldSelectdedState = this.state; var newSelectedState = this.props.select(nextState); if ( !isObjectNotNull(oldSelectdedState, newSelectedState) || !isShallowEqual(oldSelectdedState, newSelectedState) ) { this.setState(newSelectedState); } }; State.prototype.componentDidMount = function componentDidMount () { if (!this.props.state) { this.subscriptionId = this.broadcast.subscribe(this.setStateIfNeeded); // To handle the case where a child component may have triggered a state change in // its cWM/cDM, we have to re-run the selector and maybe re-render. this.setStateIfNeeded(this.broadcast.getState()); } }; State.prototype.componentWillUnmount = function componentWillUnmount () { this.subscriptionId && this.broadcast.unsubscribe(this.subscriptionId); }; State.prototype.render = function render () { return ( this.props.render( this.props.select( this.props.state ? this.state : this.broadcast.getState() ), this.update ) || null ) }; return State; }(react.Component)); State.defaultProps = { select: function (s) { return s; }, render: function () { return null; } }; State.contextTypes = { __statty__: PropTypes.object.isRequired }; State.propTypes = { state: PropTypes.object, render: PropTypes.func, select: PropTypes.func }; function createBroadcast (initialState) { var listeners = {}; var id = 1; var _state = initialState; function getState () { return _state } function setState (state) { _state = state; var keys = Object.keys(listeners); var i = 0; var len = keys.length; for (; i < len; i++) { // if a listener gets unsubscribed during setState we just skip it if (listeners[keys[i]]) { listeners[keys[i]](state); } } } // subscribe to changes and return the subscriptionId function subscribe (listener) { if (typeof listener !== 'function') { throw new Error('listener must be a function.') } var currentId = id; listeners[currentId] = listener; id += 1; return currentId } // remove subscription by removing the listener function function unsubscribe (id) { listeners[id] = undefined; } return { getState: getState, setState: setState, subscribe: subscribe, unsubscribe: unsubscribe } } var Provider = (function (Component$$1) { function Provider (props, context) { Component$$1.call(this, props, context); this.broadcast = createBroadcast(props.state); } if ( Component$$1 ) Provider.__proto__ = Component$$1; Provider.prototype = Object.create( Component$$1 && Component$$1.prototype ); Provider.prototype.constructor = Provider; Provider.prototype.getChildContext = function getChildContext () { return { __statty__: { broadcast: this.broadcast, inspect: this.props.inspect } } }; Provider.prototype.render = function render () { var children = this.props.children; return Array.isArray(children) ? children[0] : children }; return Provider; }(react.Component)); Provider.childContextTypes = { __statty__: PropTypes.object }; Provider.propTypes = { inspect: PropTypes.func, state: PropTypes.object.isRequired, children: PropTypes.node.isRequired }; exports.Provider = Provider; exports.State = State; Object.defineProperty(exports, '__esModule', { value: true }); })));