/** * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule FluxContainer * */ 'use strict'; function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var FluxContainerSubscriptions = require("./FluxContainerSubscriptions"); var React = require("react"); var invariant = require("fbjs/lib/invariant"); var shallowEqual = require("fbjs/lib/shallowEqual"); var Component = React.Component; var DEFAULT_OPTIONS = { pure: true, withProps: false, withContext: false }; /** * A FluxContainer is used to subscribe a react component to multiple stores. * The stores that are used must be returned from a static `getStores()` method. * * The component receives information from the stores via state. The state * is generated using a static `calculateState()` method that each container * must implement. A simple container may look like: * * class FooContainer extends Component { * static getStores() { * return [FooStore]; * } * * static calculateState() { * return { * foo: FooStore.getState(), * }; * } * * render() { * return ; * } * } * * module.exports = FluxContainer.create(FooContainer); * * Flux container also supports some other, more advanced use cases. If you need * to base your state off of props as well: * * class FooContainer extends Component { * ... * * static calculateState(prevState, props) { * return { * foo: FooStore.getSpecificFoo(props.id), * }; * } * * ... * } * * module.exports = FluxContainer.create(FooContainer, {withProps: true}); * * Or if your stores are passed through your props: * * class FooContainer extends Component { * ... * * static getStores(props) { * const {BarStore, FooStore} = props.stores; * return [BarStore, FooStore]; * } * * static calculateState(prevState, props) { * const {BarStore, FooStore} = props.stores; * return { * bar: BarStore.getState(), * foo: FooStore.getState(), * }; * } * * ... * } * * module.exports = FluxContainer.create(FooContainer, {withProps: true}); */ function create(Base, options) { enforceInterface(Base); // Construct the options using default, override with user values as necessary. var realOptions = _objectSpread(_objectSpread({}, DEFAULT_OPTIONS), options || {}); var getState = function getState(state, maybeProps, maybeContext) { var props = realOptions.withProps ? maybeProps : undefined; var context = realOptions.withContext ? maybeContext : undefined; return Base.calculateState(state, props, context); }; var getStores = function getStores(maybeProps, maybeContext) { var props = realOptions.withProps ? maybeProps : undefined; var context = realOptions.withContext ? maybeContext : undefined; return Base.getStores(props, context); }; // Build the container class. var ContainerClass = /*#__PURE__*/function (_Base) { _inheritsLoose(ContainerClass, _Base); function ContainerClass(props, context) { var _this; _this = _Base.call(this, props, context) || this; _defineProperty(_assertThisInitialized(_this), "_fluxContainerSubscriptions", void 0); _this._fluxContainerSubscriptions = new FluxContainerSubscriptions(); _this._fluxContainerSubscriptions.setStores(getStores(props, context)); _this._fluxContainerSubscriptions.addListener(function () { _this.setState(function (prevState, currentProps) { return getState(prevState, currentProps, context); }); }); var calculatedState = getState(undefined, props, context); _this.state = _objectSpread(_objectSpread({}, _this.state || {}), calculatedState); return _this; } var _proto = ContainerClass.prototype; _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps, nextContext) { if (_Base.prototype.UNSAFE_componentWillReceiveProps) { _Base.prototype.UNSAFE_componentWillReceiveProps.call(this, nextProps, nextContext); } if (_Base.prototype.componentWillReceiveProps) { _Base.prototype.componentWillReceiveProps.call(this, nextProps, nextContext); } if (realOptions.withProps || realOptions.withContext) { // Update both stores and state. this._fluxContainerSubscriptions.setStores(getStores(nextProps, nextContext)); this.setState(function (prevState) { return getState(prevState, nextProps, nextContext); }); } }; _proto.componentWillUnmount = function componentWillUnmount() { if (_Base.prototype.componentWillUnmount) { _Base.prototype.componentWillUnmount.call(this); } this._fluxContainerSubscriptions.reset(); }; return ContainerClass; }(Base); // Make sure we override shouldComponentUpdate only if the pure option is // specified. We can't override this above because we don't want to override // the default behavior on accident. Super works weird with react ES6 classes. var container = realOptions.pure ? createPureComponent(ContainerClass) : ContainerClass; // Update the name of the container before returning var componentName = Base.displayName || Base.name; container.displayName = 'FluxContainer(' + componentName + ')'; return container; } function createPureComponent(BaseComponent) { var PureComponent = /*#__PURE__*/function (_BaseComponent) { _inheritsLoose(PureComponent, _BaseComponent); function PureComponent() { return _BaseComponent.apply(this, arguments) || this; } var _proto2 = PureComponent.prototype; _proto2.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); }; return PureComponent; }(BaseComponent); return PureComponent; } function enforceInterface(o) { !o.getStores ? process.env.NODE_ENV !== "production" ? invariant(false, 'Components that use FluxContainer must implement `static getStores()`') : invariant(false) : void 0; !o.calculateState ? process.env.NODE_ENV !== "production" ? invariant(false, 'Components that use FluxContainer must implement `static calculateState()`') : invariant(false) : void 0; } /** * This is a way to connect stores to a functional stateless view. Here's a * simple example: * * // FooView.js * * function FooView(props) { * return
{props.value}
; * } * * module.exports = FooView; * * * // FooContainer.js * * function getStores() { * return [FooStore]; * } * * function calculateState() { * return { * value: FooStore.getState(); * }; * } * * module.exports = FluxContainer.createFunctional( * FooView, * getStores, * calculateState, * ); * */ function createFunctional(viewFn, _getStores, _calculateState, options) { var FunctionalContainer = /*#__PURE__*/function (_Component) { _inheritsLoose(FunctionalContainer, _Component); function FunctionalContainer() { var _this2; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this2 = _Component.call.apply(_Component, [this].concat(args)) || this; _defineProperty(_assertThisInitialized(_this2), "state", void 0); return _this2; } FunctionalContainer.getStores = function getStores(props, context) { return _getStores(props, context); }; FunctionalContainer.calculateState = function calculateState(prevState, props, context) { return _calculateState(prevState, props, context); }; var _proto3 = FunctionalContainer.prototype; _proto3.render = function render() { return viewFn(this.state); }; return FunctionalContainer; }(Component); // Update the name of the component before creating the container. var viewFnName = viewFn.displayName || viewFn.name || 'FunctionalContainer'; FunctionalContainer.displayName = viewFnName; return create(FunctionalContainer, options); } module.exports = { create: create, createFunctional: createFunctional };