UNPKG

reshow-flux

Version:
139 lines (132 loc) 3.53 kB
// @ts-check import { useState, useEffect, useDebugValue } from "react"; import { useMounted } from "reshow-hooks"; import { T_TRUE, T_FALSE } from "reshow-constant"; import getStore from "./getStore.mjs"; var handleShouldComponentUpdate = function handleShouldComponentUpdate(_ref) { var { calOptions, shouldComponentUpdate, calculateState, prev, props } = _ref; var nextState = calculateState(prev.state, calOptions); var bUpdate = shouldComponentUpdate ? shouldComponentUpdate({ prev, nextProps: props, nextState }) : nextState !== prev.state; if (bUpdate) { return { props, state: nextState, __init__: T_TRUE }; } else { prev.__init__ = T_TRUE; return prev; } }; /** * @template StateType * @template ActionType * @typedef {import("reshow-flux-base").StoreObject<StateType, ActionType>} StoreObject */ /** * @template StateType * @template ActionType * @typedef {object} UseConnectWithStore * @property {StoreObject<StateType, ActionType>} store */ /** * @template StateType * * @callback CalculateStateCallback * @param {StateType|any} prevState * @param {any} calculateOptions * @returns {StateType} */ /** * @template StateType * * @callback GetStateCallback * @param {any} props * @returns {StateType} */ /** * @template StateType * @template ActionType * * @typedef {object} UseConnectOption * @property {CalculateStateCallback<StateType>} calculateState * @property {boolean} [shouldComponentUpdate] * @property {function(any):StoreObject<StateType, ActionType>} [storeLocator] * @property {string} [displayName] */ var useConnect = /** * @template StateType * @template ActionType * * @param {UseConnectOption<StateType, ActionType>} inputOptions * @returns {GetStateCallback<StateType>} */ function useConnect(inputOptions) { return function (props) { /** * @type UseConnectWithStore<StateType, ActionType> & UseConnectOption<StateType, ActionType> */ var options = getStore({ options: inputOptions, props }); var { calculateState, shouldComponentUpdate, displayName = "useConnect" } = options; var calOptions = /**@type any*/options; useDebugValue(displayName); var [data, setData] = useState(function () { return { props, state: calculateState({}, calOptions), __init__: T_FALSE }; }); var isMount = useMounted(); useEffect(function () { var handleChange = function handleChange(/** @type any */storeSyncState) { if (T_TRUE === isMount()) { /** * Why storeSyncState? * * It's useful for synchronous programing to get correct data, * when it pass from reducer directly. */ calOptions.storeSyncState = storeSyncState; setData(function (prev) { return handleShouldComponentUpdate({ calOptions, calculateState, shouldComponentUpdate, prev, props }); }); } return storeSyncState; }; if (!data.__init__ || data.props !== props) { handleChange(options.store.getState()); } options.store.addListener(handleChange); return function () { options.store.removeListener(handleChange); }; }, props.renewProps ? [props] : []); return /**@type StateType*/data.state || {}; }; }; export default useConnect;