@modern-js-reduck/react
Advanced tools
+20
-0
| # @modern-js-reduck/react | ||
| ## 1.0.0-rc.10 | ||
| ### Patch Changes | ||
| - a7bd932: release: rc.7 | ||
| - 26d5144: fix(type): actions can return void | ||
| - 9452589: fix: ts type | ||
| - a7bd932: fix: use model State type | ||
| - feat: useLocalModel support | ||
| - a7bd932: fix: model type | ||
| - a7bd932: fix: model<State> when State passed use State | ||
| - Updated dependencies [a7bd932] | ||
| - Updated dependencies [26d5144] | ||
| - Updated dependencies [9452589] | ||
| - Updated dependencies [a7bd932] | ||
| - Updated dependencies [undefined] | ||
| - Updated dependencies [a7bd932] | ||
| - Updated dependencies [a7bd932] | ||
| - @modern-js-reduck/store@1.0.0-rc.10 | ||
| ## 1.0.0-rc.9 | ||
@@ -4,0 +24,0 @@ |
@@ -10,3 +10,3 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } | ||
| import '@testing-library/jest-dom/extend-expect'; | ||
| import { useModel, Provider, createApp, useStaticModel } from '..'; | ||
| import { useModel, Provider, createApp, useStaticModel, useLocalModel } from '..'; | ||
| import { jsx as _jsx } from "react/jsx-runtime"; | ||
@@ -51,3 +51,3 @@ import { Fragment as _Fragment } from "react/jsx-runtime"; | ||
| }); | ||
| test('Global Provider and useModel should works', () => { | ||
| test('Global Provider and useModel should work', () => { | ||
| const result = render( /*#__PURE__*/_jsx(Provider, { | ||
@@ -60,10 +60,10 @@ children: /*#__PURE__*/_jsx(App, {}) | ||
| }); | ||
| test('Local Provider and useModel should works', () => { | ||
| test('Local Provider and useModel should work', () => { | ||
| const { | ||
| Provider: LocalProvider, | ||
| useModel: useLocalModel | ||
| useModel: useLModel | ||
| } = createApp({}); | ||
| const SubApp = () => { | ||
| const [state, actions] = useLocalModel(countModel); | ||
| const [state, actions] = useLModel(countModel); | ||
| return /*#__PURE__*/_jsxs(_Fragment, { | ||
@@ -123,2 +123,31 @@ children: [/*#__PURE__*/_jsx("div", { | ||
| }); | ||
| test('useLocalModel should work', () => { | ||
| function Container() { | ||
| const [state, actions] = useLocalModel(countModel); | ||
| const [state1, actions1] = useLocalModel(countModel); | ||
| return /*#__PURE__*/_jsxs("div", { | ||
| children: [/*#__PURE__*/_jsxs("div", { | ||
| children: ["state: ", state.value] | ||
| }), /*#__PURE__*/_jsxs("div", { | ||
| children: ["state1: ", state1.value] | ||
| }), /*#__PURE__*/_jsx("button", { | ||
| type: "button", | ||
| onClick: () => actions.add(), | ||
| children: "actions add" | ||
| }), /*#__PURE__*/_jsx("button", { | ||
| type: "button", | ||
| onClick: () => actions1.add(), | ||
| children: "actions1 add" | ||
| })] | ||
| }); | ||
| } | ||
| const result = render( /*#__PURE__*/_jsx(Container, {})); | ||
| fireEvent.click(result.getByText('actions add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 1')).toBeInTheDocument(); | ||
| fireEvent.click(result.getByText('actions1 add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 2')).toBeInTheDocument(); | ||
| }); | ||
| }); |
@@ -32,3 +32,3 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } | ||
| store: storeFromProps, | ||
| _config | ||
| config: _config | ||
| } = props; | ||
@@ -46,9 +46,3 @@ const store = storeFromProps || createStore(_objectSpread(_objectSpread({}, config), _config)); | ||
| const useModel = (...args) => { | ||
| const context = useContext(Context); | ||
| invariant(Boolean(context), 'You should wrap your Component in CreateApp().Provider.'); | ||
| const { | ||
| store, | ||
| batchManager | ||
| } = context; | ||
| const createUseModel = (store, batchManager) => (...args) => { | ||
| const initialValue = useMemo(() => store.use(...args), []); | ||
@@ -77,2 +71,12 @@ const [modelValue, setModelValue] = useState(initialValue); | ||
| const useModel = (...args) => { | ||
| const context = useContext(Context); | ||
| invariant(Boolean(context), `You should wrap your Component in CreateApp().Provider.`); | ||
| const { | ||
| store, | ||
| batchManager | ||
| } = context; | ||
| return useMemo(() => createUseModel(store, batchManager), [store])(...args); | ||
| }; | ||
| const useStaticModel = (...args) => { | ||
@@ -85,3 +89,4 @@ const context = useContext(Context); | ||
| const [state, actions, subscribe] = useMemo(() => store.use(...args), []); | ||
| const value = useRef([state, actions, subscribe]); | ||
| const value = useRef([// deep clone state in case mutate origin state accidentlly. | ||
| JSON.parse(JSON.stringify(state)), actions, subscribe]); | ||
| useEffect(() => { | ||
@@ -104,6 +109,20 @@ if (Object.prototype.toString.call(state) === '[object Object]') { | ||
| const useLocalModel = (...args) => { | ||
| const [store, batchManager] = useMemo(() => { | ||
| const localStoreConfig = { | ||
| enhanders: (config === null || config === void 0 ? void 0 : config.enhancers) || [], | ||
| middlewares: (config === null || config === void 0 ? void 0 : config.middlewares) || [], | ||
| plugins: config === null || config === void 0 ? void 0 : config.plugins | ||
| }; | ||
| const reuckStore = createStore(localStoreConfig); | ||
| return [reuckStore, createBatchManager(reuckStore)]; | ||
| }, []); | ||
| return useMemo(() => createUseModel(store, batchManager), [])(...args); | ||
| }; | ||
| return { | ||
| Provider, | ||
| useModel, | ||
| useStaticModel | ||
| useStaticModel, | ||
| useLocalModel | ||
| }; | ||
@@ -110,0 +129,0 @@ }; |
@@ -5,4 +5,5 @@ import createApp from "./createApp"; | ||
| useModel, | ||
| useStaticModel | ||
| useStaticModel, | ||
| useLocalModel | ||
| } = createApp({}); | ||
| export { Provider, useModel, createApp, useStaticModel }; | ||
| export { Provider, useModel, createApp, useStaticModel, useLocalModel }; |
@@ -55,3 +55,3 @@ "use strict"; | ||
| }); | ||
| test('Global Provider and useModel should works', () => { | ||
| test('Global Provider and useModel should work', () => { | ||
| const result = (0, _react.render)( /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Provider, { | ||
@@ -66,10 +66,10 @@ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(App, {}) | ||
| }); | ||
| test('Local Provider and useModel should works', () => { | ||
| test('Local Provider and useModel should work', () => { | ||
| const { | ||
| Provider: LocalProvider, | ||
| useModel: useLocalModel | ||
| useModel: useLModel | ||
| } = (0, _.createApp)({}); | ||
| const SubApp = () => { | ||
| const [state, actions] = useLocalModel(countModel); | ||
| const [state, actions] = useLModel(countModel); | ||
| return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { | ||
@@ -135,2 +135,35 @@ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", { | ||
| }); | ||
| test('useLocalModel should work', () => { | ||
| function Container() { | ||
| const [state, actions] = (0, _.useLocalModel)(countModel); | ||
| const [state1, actions1] = (0, _.useLocalModel)(countModel); | ||
| return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { | ||
| children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { | ||
| children: ["state: ", state.value] | ||
| }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { | ||
| children: ["state1: ", state1.value] | ||
| }), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", { | ||
| type: "button", | ||
| onClick: () => actions.add(), | ||
| children: "actions add" | ||
| }), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", { | ||
| type: "button", | ||
| onClick: () => actions1.add(), | ||
| children: "actions1 add" | ||
| })] | ||
| }); | ||
| } | ||
| const result = (0, _react.render)( /*#__PURE__*/(0, _jsxRuntime.jsx)(Container, {})); | ||
| _react.fireEvent.click(result.getByText('actions add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 1')).toBeInTheDocument(); | ||
| _react.fireEvent.click(result.getByText('actions1 add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 2')).toBeInTheDocument(); | ||
| }); | ||
| }); |
@@ -45,3 +45,3 @@ "use strict"; | ||
| store: storeFromProps, | ||
| _config | ||
| config: _config | ||
| } = props; | ||
@@ -59,9 +59,3 @@ const store = storeFromProps || (0, _store.createStore)(_objectSpread(_objectSpread({}, config), _config)); | ||
| const useModel = (...args) => { | ||
| const context = (0, _react.useContext)(Context); | ||
| (0, _invariant.default)(Boolean(context), 'You should wrap your Component in CreateApp().Provider.'); | ||
| const { | ||
| store, | ||
| batchManager | ||
| } = context; | ||
| const createUseModel = (store, batchManager) => (...args) => { | ||
| const initialValue = (0, _react.useMemo)(() => store.use(...args), []); | ||
@@ -90,2 +84,12 @@ const [modelValue, setModelValue] = (0, _react.useState)(initialValue); | ||
| const useModel = (...args) => { | ||
| const context = (0, _react.useContext)(Context); | ||
| (0, _invariant.default)(Boolean(context), `You should wrap your Component in CreateApp().Provider.`); | ||
| const { | ||
| store, | ||
| batchManager | ||
| } = context; | ||
| return (0, _react.useMemo)(() => createUseModel(store, batchManager), [store])(...args); | ||
| }; | ||
| const useStaticModel = (...args) => { | ||
@@ -98,3 +102,4 @@ const context = (0, _react.useContext)(Context); | ||
| const [state, actions, subscribe] = (0, _react.useMemo)(() => store.use(...args), []); | ||
| const value = (0, _react.useRef)([state, actions, subscribe]); | ||
| const value = (0, _react.useRef)([// deep clone state in case mutate origin state accidentlly. | ||
| JSON.parse(JSON.stringify(state)), actions, subscribe]); | ||
| (0, _react.useEffect)(() => { | ||
@@ -117,6 +122,20 @@ if (Object.prototype.toString.call(state) === '[object Object]') { | ||
| const useLocalModel = (...args) => { | ||
| const [store, batchManager] = (0, _react.useMemo)(() => { | ||
| const localStoreConfig = { | ||
| enhanders: (config === null || config === void 0 ? void 0 : config.enhancers) || [], | ||
| middlewares: (config === null || config === void 0 ? void 0 : config.middlewares) || [], | ||
| plugins: config === null || config === void 0 ? void 0 : config.plugins | ||
| }; | ||
| const reuckStore = (0, _store.createStore)(localStoreConfig); | ||
| return [reuckStore, (0, _batchManager.createBatchManager)(reuckStore)]; | ||
| }, []); | ||
| return (0, _react.useMemo)(() => createUseModel(store, batchManager), [])(...args); | ||
| }; | ||
| return { | ||
| Provider, | ||
| useModel, | ||
| useStaticModel | ||
| useStaticModel, | ||
| useLocalModel | ||
| }; | ||
@@ -123,0 +142,0 @@ }; |
@@ -13,3 +13,3 @@ "use strict"; | ||
| }); | ||
| exports.useStaticModel = exports.useModel = void 0; | ||
| exports.useStaticModel = exports.useModel = exports.useLocalModel = void 0; | ||
@@ -23,6 +23,8 @@ var _createApp = _interopRequireDefault(require("./createApp")); | ||
| useModel, | ||
| useStaticModel | ||
| useStaticModel, | ||
| useLocalModel | ||
| } = (0, _createApp.default)({}); | ||
| exports.useLocalModel = useLocalModel; | ||
| exports.useStaticModel = useStaticModel; | ||
| exports.useModel = useModel; | ||
| exports.Provider = Provider; |
@@ -22,3 +22,3 @@ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } | ||
| import '@testing-library/jest-dom/extend-expect'; | ||
| import { useModel, Provider, createApp, useStaticModel } from '..'; | ||
| import { useModel, Provider, createApp, useStaticModel, useLocalModel } from '..'; | ||
| import { jsx as _jsx } from "react/jsx-runtime"; | ||
@@ -68,3 +68,3 @@ import { Fragment as _Fragment } from "react/jsx-runtime"; | ||
| }); | ||
| test('Global Provider and useModel should works', function () { | ||
| test('Global Provider and useModel should work', function () { | ||
| var result = render( /*#__PURE__*/_jsx(Provider, { | ||
@@ -77,12 +77,12 @@ children: /*#__PURE__*/_jsx(App, {}) | ||
| }); | ||
| test('Local Provider and useModel should works', function () { | ||
| test('Local Provider and useModel should work', function () { | ||
| var _createApp2 = createApp({}), | ||
| LocalProvider = _createApp2.Provider, | ||
| useLocalModel = _createApp2.useModel; | ||
| useLModel = _createApp2.useModel; | ||
| var SubApp = function SubApp() { | ||
| var _useLocalModel = useLocalModel(countModel), | ||
| _useLocalModel2 = _slicedToArray(_useLocalModel, 2), | ||
| state = _useLocalModel2[0], | ||
| actions = _useLocalModel2[1]; | ||
| var _useLModel = useLModel(countModel), | ||
| _useLModel2 = _slicedToArray(_useLModel, 2), | ||
| state = _useLModel2[0], | ||
| actions = _useLModel2[1]; | ||
@@ -152,2 +152,43 @@ return /*#__PURE__*/_jsxs(_Fragment, { | ||
| }); | ||
| test('useLocalModel should work', function () { | ||
| function Container() { | ||
| var _useLocalModel = useLocalModel(countModel), | ||
| _useLocalModel2 = _slicedToArray(_useLocalModel, 2), | ||
| state = _useLocalModel2[0], | ||
| actions = _useLocalModel2[1]; | ||
| var _useLocalModel3 = useLocalModel(countModel), | ||
| _useLocalModel4 = _slicedToArray(_useLocalModel3, 2), | ||
| state1 = _useLocalModel4[0], | ||
| actions1 = _useLocalModel4[1]; | ||
| return /*#__PURE__*/_jsxs("div", { | ||
| children: [/*#__PURE__*/_jsxs("div", { | ||
| children: ["state: ", state.value] | ||
| }), /*#__PURE__*/_jsxs("div", { | ||
| children: ["state1: ", state1.value] | ||
| }), /*#__PURE__*/_jsx("button", { | ||
| type: "button", | ||
| onClick: function onClick() { | ||
| return actions.add(); | ||
| }, | ||
| children: "actions add" | ||
| }), /*#__PURE__*/_jsx("button", { | ||
| type: "button", | ||
| onClick: function onClick() { | ||
| return actions1.add(); | ||
| }, | ||
| children: "actions1 add" | ||
| })] | ||
| }); | ||
| } | ||
| var result = render( /*#__PURE__*/_jsx(Container, {})); | ||
| fireEvent.click(result.getByText('actions add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 1')).toBeInTheDocument(); | ||
| fireEvent.click(result.getByText('actions1 add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 2')).toBeInTheDocument(); | ||
| }); | ||
| }); |
@@ -45,3 +45,3 @@ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } | ||
| storeFromProps = props.store, | ||
| _config = props._config; | ||
| _config = props.config; | ||
| var store = storeFromProps || createStore(_objectSpread(_objectSpread({}, config), _config)); | ||
@@ -58,41 +58,49 @@ var batchManager = createBatchManager(store); | ||
| var useModel = function useModel() { | ||
| for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
| args[_key] = arguments[_key]; | ||
| } | ||
| var createUseModel = function createUseModel(store, batchManager) { | ||
| return function () { | ||
| for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
| args[_key] = arguments[_key]; | ||
| } | ||
| var context = useContext(Context); | ||
| invariant(Boolean(context), 'You should wrap your Component in CreateApp().Provider.'); | ||
| var store = context.store, | ||
| batchManager = context.batchManager; | ||
| var initialValue = useMemo(function () { | ||
| return store.use.apply(store, args); | ||
| }, []); | ||
| var initialValue = useMemo(function () { | ||
| return store.use.apply(store, args); | ||
| }, []); | ||
| var _useState = useState(initialValue), | ||
| _useState2 = _slicedToArray(_useState, 2), | ||
| modelValue = _useState2[0], | ||
| setModelValue = _useState2[1]; | ||
| var _useState = useState(initialValue), | ||
| _useState2 = _slicedToArray(_useState, 2), | ||
| modelValue = _useState2[0], | ||
| setModelValue = _useState2[1]; | ||
| var lastValueRef = useRef(initialValue); | ||
| useEffect(function () { | ||
| var unsubsribe = initialValue[2](function () { | ||
| var newValue = store.use.apply(store, args); | ||
| var lastValueRef = useRef(initialValue); | ||
| useEffect(function () { | ||
| var unsubsribe = initialValue[2](function () { | ||
| var newValue = store.use.apply(store, args); | ||
| if (!shadowEqual(lastValueRef.current[0], newValue[0]) || !shadowEqual(lastValueRef.current[1], newValue[1])) { | ||
| batchManager.pushUpdate(function () { | ||
| setModelValue(newValue); | ||
| lastValueRef.current = newValue; | ||
| }); | ||
| } | ||
| }); | ||
| batchManager.addModels.apply(batchManager, args); | ||
| return function () { | ||
| unsubsribe(); | ||
| batchManager.removeModels.apply(batchManager, args); | ||
| }; | ||
| }, []); | ||
| return modelValue; | ||
| if (!shadowEqual(lastValueRef.current[0], newValue[0]) || !shadowEqual(lastValueRef.current[1], newValue[1])) { | ||
| batchManager.pushUpdate(function () { | ||
| setModelValue(newValue); | ||
| lastValueRef.current = newValue; | ||
| }); | ||
| } | ||
| }); | ||
| batchManager.addModels.apply(batchManager, args); | ||
| return function () { | ||
| unsubsribe(); | ||
| batchManager.removeModels.apply(batchManager, args); | ||
| }; | ||
| }, []); | ||
| return modelValue; | ||
| }; | ||
| }; | ||
| var useModel = function useModel() { | ||
| var context = useContext(Context); | ||
| invariant(Boolean(context), "You should wrap your Component in CreateApp().Provider."); | ||
| var store = context.store, | ||
| batchManager = context.batchManager; | ||
| return useMemo(function () { | ||
| return createUseModel(store, batchManager); | ||
| }, [store]).apply(void 0, arguments); | ||
| }; | ||
| var useStaticModel = function useStaticModel() { | ||
@@ -115,3 +123,4 @@ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
| var value = useRef([state, actions, subscribe]); | ||
| var value = useRef([// deep clone state in case mutate origin state accidentlly. | ||
| JSON.parse(JSON.stringify(state)), actions, subscribe]); | ||
| useEffect(function () { | ||
@@ -138,6 +147,26 @@ if (Object.prototype.toString.call(state) === '[object Object]') { | ||
| var useLocalModel = function useLocalModel() { | ||
| var _useMemo3 = useMemo(function () { | ||
| var localStoreConfig = { | ||
| enhanders: (config === null || config === void 0 ? void 0 : config.enhancers) || [], | ||
| middlewares: (config === null || config === void 0 ? void 0 : config.middlewares) || [], | ||
| plugins: config === null || config === void 0 ? void 0 : config.plugins | ||
| }; | ||
| var reuckStore = createStore(localStoreConfig); | ||
| return [reuckStore, createBatchManager(reuckStore)]; | ||
| }, []), | ||
| _useMemo4 = _slicedToArray(_useMemo3, 2), | ||
| store = _useMemo4[0], | ||
| batchManager = _useMemo4[1]; | ||
| return useMemo(function () { | ||
| return createUseModel(store, batchManager); | ||
| }, []).apply(void 0, arguments); | ||
| }; | ||
| return { | ||
| Provider: Provider, | ||
| useModel: useModel, | ||
| useStaticModel: useStaticModel | ||
| useStaticModel: useStaticModel, | ||
| useLocalModel: useLocalModel | ||
| }; | ||
@@ -144,0 +173,0 @@ }; |
@@ -6,4 +6,5 @@ import createApp from "./createApp"; | ||
| useModel = _createApp.useModel, | ||
| useStaticModel = _createApp.useStaticModel; | ||
| useStaticModel = _createApp.useStaticModel, | ||
| useLocalModel = _createApp.useLocalModel; | ||
| export { Provider, useModel, createApp, useStaticModel }; | ||
| export { Provider, useModel, createApp, useStaticModel, useLocalModel }; |
@@ -8,8 +8,11 @@ import { createStore } from '@modern-js-reduck/store'; | ||
| Provider: (props: PropsWithChildren<{ | ||
| store?: Store; | ||
| _config?: Config; | ||
| store?: (import("redux").Store<any, import("redux").AnyAction> & { | ||
| use: UseModel; | ||
| }) | undefined; | ||
| config?: Config; | ||
| }>) => JSX.Element; | ||
| useModel: UseModel; | ||
| useStaticModel: UseModel; | ||
| useLocalModel: UseModel; | ||
| }; | ||
| export default createApp; |
@@ -7,4 +7,4 @@ /// <reference types="react" /> | ||
| }) | undefined; | ||
| _config?: import("@modern-js-reduck/store/dist/types/types").StoreConfig | undefined; | ||
| }>) => JSX.Element, useModel: import("@modern-js-reduck/store/dist/types/types").UseModel, useStaticModel: import("@modern-js-reduck/store/dist/types/types").UseModel; | ||
| export { Provider, useModel, createApp, useStaticModel }; | ||
| config?: import("@modern-js-reduck/store/dist/types/types").StoreConfig | undefined; | ||
| }>) => JSX.Element, useModel: import("@modern-js-reduck/store/dist/types/types").UseModel, useStaticModel: import("@modern-js-reduck/store/dist/types/types").UseModel, useLocalModel: import("@modern-js-reduck/store/dist/types/types").UseModel; | ||
| export { Provider, useModel, createApp, useStaticModel, useLocalModel }; |
+2
-2
| { | ||
| "name": "@modern-js-reduck/react", | ||
| "version": "1.0.0-rc.9", | ||
| "version": "1.0.0-rc.10", | ||
| "jsnext:source": "./src/index.ts", | ||
@@ -20,3 +20,3 @@ "types": "./dist/types/index.d.ts", | ||
| "@babel/runtime": "^7", | ||
| "@modern-js-reduck/store": "^1.0.0-rc.9", | ||
| "@modern-js-reduck/store": "^1.0.0-rc.10", | ||
| "invariant": "^2.2.4" | ||
@@ -23,0 +23,0 @@ }, |
| import { model } from '@modern-js-reduck/store'; | ||
| import { render, fireEvent } from '@testing-library/react'; | ||
| import '@testing-library/jest-dom/extend-expect'; | ||
| import { useModel, Provider, createApp, useStaticModel } from '..'; | ||
| import { | ||
| useModel, | ||
| Provider, | ||
| createApp, | ||
| useStaticModel, | ||
| useLocalModel, | ||
| } from '..'; | ||
@@ -41,3 +47,3 @@ const countModel = model('name').define({ | ||
| test('Global Provider and useModel should works', () => { | ||
| test('Global Provider and useModel should work', () => { | ||
| const result = render( | ||
@@ -56,7 +62,7 @@ <Provider> | ||
| test('Local Provider and useModel should works', () => { | ||
| const { Provider: LocalProvider, useModel: useLocalModel } = createApp({}); | ||
| test('Local Provider and useModel should work', () => { | ||
| const { Provider: LocalProvider, useModel: useLModel } = createApp({}); | ||
| const SubApp = () => { | ||
| const [state, actions] = useLocalModel(countModel); | ||
| const [state, actions] = useLModel(countModel); | ||
@@ -131,2 +137,32 @@ return ( | ||
| }); | ||
| test('useLocalModel should work', () => { | ||
| function Container() { | ||
| const [state, actions] = useLocalModel(countModel); | ||
| const [state1, actions1] = useLocalModel(countModel); | ||
| return ( | ||
| <div> | ||
| <div>state: {state.value}</div> | ||
| <div>state1: {state1.value}</div> | ||
| <button type="button" onClick={() => actions.add()}> | ||
| actions add | ||
| </button> | ||
| <button type="button" onClick={() => actions1.add()}> | ||
| actions1 add | ||
| </button> | ||
| </div> | ||
| ); | ||
| } | ||
| const result = render(<Container />); | ||
| fireEvent.click(result.getByText('actions add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 1')).toBeInTheDocument(); | ||
| fireEvent.click(result.getByText('actions1 add')); | ||
| expect(result.getByText('state: 2')).toBeInTheDocument(); | ||
| expect(result.getByText('state1: 2')).toBeInTheDocument(); | ||
| }); | ||
| }); |
+57
-32
@@ -40,5 +40,5 @@ import { createStore } from '@modern-js-reduck/store'; | ||
| const Provider = ( | ||
| props: PropsWithChildren<{ store?: Store; _config?: Config }>, | ||
| props: PropsWithChildren<{ store?: Store; config?: Config }>, | ||
| ) => { | ||
| const { children, store: storeFromProps, _config } = props; | ||
| const { children, store: storeFromProps, config: _config } = props; | ||
| const store = storeFromProps || createStore({ ...config, ..._config }); | ||
@@ -54,2 +54,36 @@ const batchManager = createBatchManager(store); | ||
| const createUseModel = | ||
| (store: Store, batchManager: ReturnType<typeof createBatchManager>) => | ||
| (...args: any[]) => { | ||
| const initialValue = useMemo(() => store.use(...args), []); | ||
| const [modelValue, setModelValue] = useState(initialValue); | ||
| const lastValueRef = useRef<ReturnType<typeof store.use>>(initialValue); | ||
| useEffect(() => { | ||
| const unsubsribe = initialValue[2](() => { | ||
| const newValue = store.use(...args); | ||
| if ( | ||
| !shadowEqual(lastValueRef.current[0], newValue[0]) || | ||
| !shadowEqual(lastValueRef.current[1], newValue[1]) | ||
| ) { | ||
| batchManager.pushUpdate(() => { | ||
| setModelValue(newValue); | ||
| lastValueRef.current = newValue; | ||
| }); | ||
| } | ||
| }); | ||
| batchManager.addModels(...args); | ||
| return () => { | ||
| unsubsribe(); | ||
| batchManager.removeModels(...args); | ||
| }; | ||
| }, []); | ||
| return modelValue; | ||
| }; | ||
| const useModel: Store['use'] = (...args: any[]) => { | ||
@@ -60,35 +94,8 @@ const context = useContext(Context); | ||
| Boolean(context), | ||
| 'You should wrap your Component in CreateApp().Provider.', | ||
| `You should wrap your Component in CreateApp().Provider.`, | ||
| ); | ||
| const { store, batchManager } = context; | ||
| const initialValue = useMemo(() => store.use(...args), []); | ||
| const [modelValue, setModelValue] = useState(initialValue); | ||
| const lastValueRef = useRef<ReturnType<typeof store.use>>(initialValue); | ||
| useEffect(() => { | ||
| const unsubsribe = initialValue[2](() => { | ||
| const newValue = store.use(...args); | ||
| if ( | ||
| !shadowEqual(lastValueRef.current[0], newValue[0]) || | ||
| !shadowEqual(lastValueRef.current[1], newValue[1]) | ||
| ) { | ||
| batchManager.pushUpdate(() => { | ||
| setModelValue(newValue); | ||
| lastValueRef.current = newValue; | ||
| }); | ||
| } | ||
| }); | ||
| batchManager.addModels(...args); | ||
| return () => { | ||
| unsubsribe(); | ||
| batchManager.removeModels(...args); | ||
| }; | ||
| }, []); | ||
| return modelValue; | ||
| return useMemo(() => createUseModel(store, batchManager), [store])(...args); | ||
| }; | ||
@@ -107,3 +114,4 @@ | ||
| const value = useRef<ReturnType<UseModel> | any>([ | ||
| state, | ||
| // deep clone state in case mutate origin state accidentlly. | ||
| JSON.parse(JSON.stringify(state)), | ||
| actions, | ||
@@ -133,2 +141,18 @@ subscribe, | ||
| const useLocalModel: Store['use'] = (...args: any[]) => { | ||
| const [store, batchManager] = useMemo(() => { | ||
| const localStoreConfig = { | ||
| enhanders: config?.enhancers || [], | ||
| middlewares: config?.middlewares || [], | ||
| plugins: config?.plugins, | ||
| }; | ||
| const reuckStore = createStore(localStoreConfig); | ||
| return [reuckStore, createBatchManager(reuckStore)]; | ||
| }, []); | ||
| return useMemo(() => createUseModel(store, batchManager), [])(...args); | ||
| }; | ||
| return { | ||
@@ -138,2 +162,3 @@ Provider, | ||
| useStaticModel, | ||
| useLocalModel, | ||
| }; | ||
@@ -140,0 +165,0 @@ }; |
+2
-2
| import createApp from './createApp'; | ||
| const { Provider, useModel, useStaticModel } = createApp({}); | ||
| const { Provider, useModel, useStaticModel, useLocalModel } = createApp({}); | ||
| export { Provider, useModel, createApp, useStaticModel }; | ||
| export { Provider, useModel, createApp, useStaticModel, useLocalModel }; |
89722
12.24%2090
11.23%