@modern-js-reduck/react
Version:
The meta-framework suite designed from scratch for frontend-focused modern web development.
218 lines (217 loc) • 7.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for (var name in all)
Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
getDefaultPlugins: () => getDefaultPlugins,
createApp: () => createApp
});
const _interop_require_default = require("@swc/helpers/_/_interop_require_default");
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _jsxruntime = require("react/jsx-runtime");
const _store = require("@modern-js-reduck/store");
const _react = /* @__PURE__ */ _interop_require_wildcard._(require("react"));
const _invariant = /* @__PURE__ */ _interop_require_default._(require("invariant"));
const _plugineffects = /* @__PURE__ */ _interop_require_default._(require("@modern-js-reduck/plugin-effects"));
const _pluginimmutable = /* @__PURE__ */ _interop_require_default._(require("@modern-js-reduck/plugin-immutable"));
const _pluginautoactions = /* @__PURE__ */ _interop_require_default._(require("@modern-js-reduck/plugin-auto-actions"));
const _plugindevtools = /* @__PURE__ */ _interop_require_default._(require("@modern-js-reduck/plugin-devtools"));
const _useIsomorphicLayoutEffect = require("./utils/useIsomorphicLayoutEffect");
const _batchManager = require("./batchManager");
const { useSyncExternalStore } = _react.default;
const isReact18 = useSyncExternalStore !== void 0;
const shallowEqual = (a, b) => {
if (Object.prototype.toString.call(a) !== "[object Object]" || Object.prototype.toString.call(b) !== "[object Object]") {
return a === b;
}
if (Object.keys(a).length !== Object.keys(b).length) {
return false;
}
return Object.keys(a).every((key) => Object.prototype.hasOwnProperty.call(b, key) && a[key] === b[key]);
};
const getDefaultPlugins = (config) => {
const defaultConfig = {
devTools: true,
autoActions: true
};
const finalConfig = {
...defaultConfig,
...config
};
const plugins = [
_pluginimmutable.default,
_plugineffects.default
];
if (finalConfig.autoActions) {
plugins.push(_pluginautoactions.default);
}
const devToolsOptions = finalConfig.devTools;
if (devToolsOptions) {
plugins.push((0, _plugindevtools.default)(typeof devToolsOptions === "object" ? devToolsOptions : void 0));
}
return plugins;
};
const createApp = (config = {}) => {
let configFromProvider;
const Context = /* @__PURE__ */ (0, _react.createContext)(null);
const defaultPlugins = getDefaultPlugins(config);
const Provider = (props) => {
const { children, store: storeFromProps, config: _config } = props;
configFromProvider = {
...config,
..._config
};
configFromProvider.plugins = configFromProvider.plugins || defaultPlugins;
const contextValue = (0, _react.useMemo)(() => {
const store = storeFromProps || (0, _store.createStore)(configFromProvider);
const batchManager = (0, _batchManager.createBatchManager)(store);
return {
store,
batchManager
};
}, [
storeFromProps,
_config
]);
return /* @__PURE__ */ (0, _jsxruntime.jsx)(Context.Provider, {
value: contextValue,
children
});
};
const createUseModel = (store) => (..._args) => {
const args = _args.flat();
const initialValue = store.use(...args);
const lastValueRef = (0, _react.useRef)(initialValue);
const getSnapshot = (0, _react.useCallback)(() => {
const newValue = store.use(...args);
if (!shallowEqual(lastValueRef.current[0], newValue[0])) {
lastValueRef.current = newValue;
return newValue;
} else {
return lastValueRef.current;
}
}, [
store,
...args
]);
const selectedState = useSyncExternalStore(
initialValue[2],
getSnapshot,
// The third parameter is required in SSR.
// The initial state should be set when createStore in hydration stage,
// so we can use the same getSnapshot to get state.
getSnapshot
);
return selectedState;
};
const legacy_createUseModel = (store, batchManager) => (..._args) => {
const args = _args.flat();
const deps = args.filter((item) => _store.utils.isModel(item));
const initialValue = (0, _react.useMemo)(() => store.use(...args), [
store,
...deps
]);
const [modelValue, setModelValue] = (0, _react.useState)(initialValue);
const lastValueRef = (0, _react.useRef)(initialValue);
const checkForUpdates = (sync = false) => {
const newValue = store.use(...args);
if (!shallowEqual(lastValueRef.current[0], newValue[0])) {
if (sync) {
setModelValue(newValue);
lastValueRef.current = newValue;
} else {
batchManager.pushUpdate(() => {
setModelValue(newValue);
lastValueRef.current = newValue;
});
}
}
};
(0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => {
const subscribe = initialValue[2];
const unsubscribe = subscribe(checkForUpdates);
batchManager.addModels(...deps);
checkForUpdates(true);
return () => {
unsubscribe();
batchManager.removeModels(...deps);
};
}, [
...deps,
initialValue,
batchManager
]);
return modelValue;
};
const useModel = (...args) => {
const context = (0, _react.useContext)(Context);
(0, _invariant.default)(Boolean(context), `You should wrap your Component with Reduck Provider.`);
const { store, batchManager } = context;
const _useModel = (0, _react.useMemo)(() => {
return isReact18 ? createUseModel(store) : legacy_createUseModel(store, batchManager);
}, [
store
]);
return _useModel(...args);
};
const useStaticModel = (...args) => {
const context = (0, _react.useContext)(Context);
(0, _invariant.default)(Boolean(context), "You should wrap your Component with Reduck Provider.");
const { store } = context;
const [state, actions, subscribe] = (0, _react.useMemo)(() => store.use(...args), []);
const value = (0, _react.useRef)([
// deep clone state in case mutate origin state accidentally.
JSON.parse(JSON.stringify(state)),
actions,
subscribe
]);
(0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => {
if (Object.prototype.toString.call(state) === "[object Object]") {
return subscribe(() => {
const [newState, newActions] = store.use(...args);
Object.assign(value.current[0], newState);
Object.assign(value.current[1], newActions);
});
}
return () => {
};
}, []);
return value.current;
};
const useLocalModel = (...args) => {
const [store, batchManager] = (0, _react.useMemo)(() => {
const finalConfig = configFromProvider;
const localStoreConfig = {
enhancers: (finalConfig === null || finalConfig === void 0 ? void 0 : finalConfig.enhancers) || [],
middlewares: (finalConfig === null || finalConfig === void 0 ? void 0 : finalConfig.middlewares) || [],
plugins: finalConfig === null || finalConfig === void 0 ? void 0 : finalConfig.plugins
};
const reduckStore = (0, _store.createStore)(localStoreConfig);
return [
reduckStore,
(0, _batchManager.createBatchManager)(reduckStore)
];
}, []);
return (0, _react.useMemo)(() => {
return isReact18 ? createUseModel(store) : legacy_createUseModel(store, batchManager);
}, [])(...args);
};
const useStore = () => {
const { store } = (0, _react.useContext)(Context);
return store;
};
return {
Provider,
useStore,
useModel,
useStaticModel,
useLocalModel
};
};