UNPKG

@xailabs/altx

Version:

Flux flavor based on alt.js

307 lines (277 loc) 15.9 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base data-ice="baseUrl" href="../../../"> <title data-ice="title">src/decorators/connect.js | API Document</title> <link type="text/css" rel="stylesheet" href="css/style.css"> <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css"> <script src="script/prettify/prettify.js"></script> <script src="script/manual.js"></script> </head> <body class="layout-container" data-ice="rootContainer"> <header> <a href="./">Home</a> <a href="identifiers.html">Reference</a> <a href="source.html">Source</a> <div class="search-box"> <span> <img src="./image/search.png"> <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span> </span> <ul class="search-result"></ul> </div> </header> <nav class="navigation" data-ice="nav"><div> <ul> <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/ImmutableStore.js~ImmutableStore.html">ImmutableStore</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-BindHandlers">BindHandlers</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-resetStores">resetStores</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getAltInstance">getAltInstance</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-setAltInstance">setAltInstance</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-callFactory">callFactory</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-callSeries">callSeries</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createActions">createActions</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createStore">createStore</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getSources">getSources</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-handlerFactory">handlerFactory</a></span></span></li> <li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">decorators</div><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-bindActions">bindActions</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-bindCalls">bindCalls</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-bindHandlers">bindHandlers</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-connect">connect</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-connectAlternative">connectAlternative</a></span></span></li> <li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">utils</div><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-flatten">flatten</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createLogger">createLogger</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getLevel">getLevel</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-setLevel">setLevel</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-logLevel">logLevel</a></span></span></li> <li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">utils/validate</div><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-creatorConstraints">creatorConstraints</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateCreator">validateCreator</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-definitionConstraints">definitionConstraints</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateDefinition">validateDefinition</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-handlerConstraints">handlerConstraints</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateHandler">validateHandler</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-loggerConstraints">loggerConstraints</a></span></span></li> </ul> </div> </nav> <div class="content" data-ice="content"><h1 data-ice="title">src/decorators/connect.js</h1> <pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">import connectToStores from &apos;alt-utils/lib/connectToStores&apos;; import React, { createElement } from &apos;react&apos;; // TODO: deprecate connectAlternative asap! /* eslint-disable */ /** * A component decorator for connecting to immutable stores. * * Basically a wrapper around `alt/utils/connectToStores`. * Adds the necessary static methods `getStores()` and `getPropsFromStores()` to the decorated component. * * - Supports multiple stores. * - Supports a simplified, string-based access to stores, with optional renaming of props. * - Supports more flexible, redux-like access to stores using mapper functions. * * ### String notation * * @example * @connect([{store: MyStore, props: [&apos;myValue&apos;, &apos;anotherValue&apos;]}]) * export default class MyComponent extends React.Component { * render() { * const {myValue, anotherValue} = this.props; * ... * } * } * * You can rename props using the ` as ` alias syntax * * @example * @connect([{ * store: PeopleStore, * props: [&apos;items as people&apos;] * }, { * store: ProductStore, * props: [&apos;items as products&apos;] * }]) * export default class MyComponent extends React.Component { * render() { * // this.props.people, this.props.products, ... * } * } * * ### Function notation * * Use mapper functions instead of strings in order to manually retrieve store values. * The function receives the store state and the component props. * * @example * @connect([{ * store: MyStore, * props: (state, props) =&gt; { * return { * item: state.get(&apos;items&apos;).filter(item =&gt; item.get(&apos;id&apos;) === props.id) * } * } * }]) * export default class MyComponent extends React.Component { * render() { * const item = this.props.item; * } * } * * Technically, you could also mix all access methods, but this defeats the purpose of simple access: * * @example * @connect([{ * store: MyStore, * props: [&apos;someProp&apos;, &apos;anotherProp&apos;, (state, props) =&gt; { * return { * item: state.get(&apos;items&apos;).filter(item =&gt; item.get(&apos;id&apos;) === props.id) * } * }, &apos;some.nested.value as foo&apos;] * }]) * export default class MyComponent extends React.Component { * ... * } * * There are however valid usecase for mixing access methods. For example, you might have keys that themselves contain dots. * For example, that is the case when using `validate.js` with nested constraints and keeping validation results in the store. * There might be an `errors` map in your storewith keys like `user.address.street`. In such a case you wouldn&apos;t be able to access those values because the dots do not * represent the actual keyPath in the tree: * * @example * @connect([{ * store, * props: [&apos;user.address.street&apos;, (state) =&gt; ({errors: state.getIn([&apos;errors&apos;, &apos;user.address.street&apos;])})] * }]) * * @see https://github.com/goatslacker/alt/blob/master/docs/utils/immutable.md * @see https://github.com/goatslacker/alt/blob/master/src/utils/connectToStores.js * * @param {Array&lt;{store: AltStore, props: Array&lt;string&gt;}&gt;} definitions - A list of objects that each define a store connection */ /* eslint-enable */ export default function connect(definitions) { return function(targetClass) { targetClass.getStores = function() { return definitions.map((def) =&gt; def.store); }; targetClass.getPropsFromStores = function(componentProps) { return definitions.reduce((result, def) =&gt; { if (typeof def.props === &apos;function&apos;) { // the props definition is itself a function. return with its result. return Object.assign(result, def.props(def.store.state, componentProps)); } // the props definition is an array. evaluate and reduce each of its elements return def.props.reduce((result, accessor) =&gt; { return Object.assign(result, mapProps(accessor, def.store.state, componentProps)); }, result); }, {}); }; return connectToStores(targetClass); }; } function mapProps(accessor, state, props) { switch (typeof accessor) { case &apos;function&apos;: return mapFuncAccessor(accessor, state, props); case &apos;string&apos;: return mapStringAccessor(accessor, state); } } function mapFuncAccessor(accessor, state, props) { return accessor(state, props); } function mapStringAccessor(accessor, state) { const {keyPath, propName} = parseAccessor(accessor); return { [propName]: state.getIn(keyPath) }; } /** * Takes the accessor defined by the component and retrieves `keyPath` and `propName` * The accessor may be the name of a top-level value in the store, or a path to a nested value. * Nested values can be accessed using a dot-separated syntax (e.g. `some.nested.value`). * * The name of the prop received by the component is the last part of the accessor in case of * a nested syntax, or the accessor itself in case of a simple top-level accessor. * * If you need to pass the value using a different prop name, you can use the ` as ` alias syntax, * e.g. `someProp as myProp` or `some.prop as myProp`. * * examples: * * &apos;someValue&apos; // {keyPath: [&apos;someValue&apos;], propName: &apos;someValue&apos;} * &apos;someValue as foo&apos; // {keyPath: [&apos;someValue&apos;], propName: &apos;foo&apos;} * &apos;some.nested.value&apos; // {keyPath: [&apos;some&apos;, &apos;nested&apos;, &apos;value&apos;], propName: &apos;value&apos;} * &apos;some.nested.value as foo&apos; // {keyPath: [&apos;some&apos;, &apos;nested&apos;, &apos;value&apos;], propName: &apos;foo&apos;} * * @param {string} string - The value accessor passed by the component decorator. * @return {object} result - A `{storeName, propName}` object * @return {string} result.keyPath - An immutablejs keyPath array to the value in the store * @return {string} result.propName - name for the prop as expected by the component */ function parseAccessor(accessor) { let keyPath, propName; if (accessor.indexOf(&apos; as &apos;) &gt; -1) { // e.g. &apos;foo as bar&apos; or &apos;some.foo as bar&apos; const parts = accessor.split(&apos; as &apos;); keyPath = parts[0].split(&apos;.&apos;); propName = parts[1]; } else { // e.g. &apos;foo&apos; or &apos;some.foo&apos; keyPath = accessor.split(&apos;.&apos;); propName = keyPath[keyPath.length - 1]; } return {keyPath, propName}; } function connectAlternative(store, mapStateToProps, WrappedComponent) { return class Connect extends React.Component { constructor(props, context) { super(props, context); const storeState = store.getState(); this.state = { storeState: mapStateToProps(storeState, props) }; } componentDidMount() { this._isMounted = true; this.storeSubscription = store.listen(this.handleStoreUpdate); } componentWillUnmount() { this._isMounted = false; if (this.storeSubscription) { store.unlisten(this.storeSubscription); } } // if we use props in mapStateToProps, // we need to run it again when props have changed componentWillReceiveProps(nextProps) { //untested! should work though if(mapStateToProps.length &gt; 1) { this.setState({storeState: mapStateToProps(store.getState(), nextProps)}); } } handleStoreUpdate = state =&gt; { if(this._isMounted) { this.setState({ storeState: mapStateToProps(state, this.props) }); } } render() { const mergedProps = { ...this.props, ...this.state.storeState }; return createElement(WrappedComponent, mergedProps); } }; } export {connectAlternative}; </code></pre> </div> <footer class="footer"> Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(0.5.2)</span><img src="./image/esdoc-logo-mini-black.png"></a> </footer> <script src="script/search_index.js"></script> <script src="script/search.js"></script> <script src="script/pretty-print.js"></script> <script src="script/inherited-summary.js"></script> <script src="script/test-summary.js"></script> <script src="script/inner-link.js"></script> <script src="script/patch-for-local.js"></script> </body> </html>