reshow-flux
Version:
The smallest react flux and Fast hook alternative
139 lines (132 loc) • 3.53 kB
JavaScript
// @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;