diff --git a/.dumi/metadata/apis/docs_apiDemos_Form.json b/.dumi/metadata/apis/docs_apiDemos_Form.json index 2394c09..f1d2dac 100644 --- a/.dumi/metadata/apis/docs_apiDemos_Form.json +++ b/.dumi/metadata/apis/docs_apiDemos_Form.json @@ -19,7 +19,8 @@ }, "tags": { "description": "Error prompt class name.", - "localKey": "API.form.global.props.form.share.errorClass" + "localKey": "API.form.global.props.form.share.errorClass", + "version": "1.3.4" } }, "labelPosition": { @@ -66,7 +67,8 @@ }, "tags": { "description": "Label class name", - "localKey": "API.form.global.props.form.share.labelClass" + "localKey": "API.form.global.props.form.share.labelClass", + "version": "1.3.4" } }, "formItemStyle": { @@ -88,7 +90,8 @@ }, "tags": { "description": "Form item class", - "localKey": "API.form.global.props.form.share.formItemClass" + "localKey": "API.form.global.props.form.share.formItemClass", + "version": "1.3.4" } }, "trigger": { @@ -115,6 +118,18 @@ "description": "Form item content style, supports object nesting writing method" } }, + "contentClassName": { + "defaultValue": null, + "name": "contentClassName", + "type": { + "name": "string" + }, + "tags": { + "description": "Content area style class name", + "localKey": "API.form.global.props.form.share.contentClass", + "version": "1.3.4" + } + }, "fullWidth": { "defaultValue": { "value": "false" @@ -197,7 +212,8 @@ }, "tags": { "description": "Form container class name.", - "localKey": "API.form.global.props.form.formClass" + "localKey": "API.form.global.props.form.formClass", + "version": "1.3.4" } }, "direction": { diff --git a/.dumi/metadata/apis/docs_apiDemos_FormItem.json b/.dumi/metadata/apis/docs_apiDemos_FormItem.json index 37cb00a..db829bd 100644 --- a/.dumi/metadata/apis/docs_apiDemos_FormItem.json +++ b/.dumi/metadata/apis/docs_apiDemos_FormItem.json @@ -125,7 +125,8 @@ }, "tags": { "description": "Error prompt class name.", - "localKey": "API.form.global.props.form.share.errorClass" + "localKey": "API.form.global.props.form.share.errorClass", + "version": "1.3.4" } }, "labelPosition": { @@ -172,7 +173,8 @@ }, "tags": { "description": "Label class name", - "localKey": "API.form.global.props.form.share.labelClass" + "localKey": "API.form.global.props.form.share.labelClass", + "version": "1.3.4" } }, "formItemStyle": { @@ -194,7 +196,8 @@ }, "tags": { "description": "Form item class", - "localKey": "API.form.global.props.form.share.formItemClass" + "localKey": "API.form.global.props.form.share.formItemClass", + "version": "1.3.4" } }, "trigger": { @@ -221,6 +224,18 @@ "description": "Form item content style, supports object nesting writing method" } }, + "contentClassName": { + "defaultValue": null, + "name": "contentClassName", + "type": { + "name": "string" + }, + "tags": { + "description": "Content area style class name", + "localKey": "API.form.global.props.form.share.contentClass", + "version": "1.3.4" + } + }, "fullWidth": { "defaultValue": { "value": "false" diff --git a/.dumi/metadata/apis/docs_apiDemos_useForm.json b/.dumi/metadata/apis/docs_apiDemos_useForm.json index 55a9318..ac3b0a4 100644 --- a/.dumi/metadata/apis/docs_apiDemos_useForm.json +++ b/.dumi/metadata/apis/docs_apiDemos_useForm.json @@ -43,7 +43,8 @@ }, "tags": { "description": "Error prompt class name.", - "localKey": "API.form.global.props.form.share.errorClass" + "localKey": "API.form.global.props.form.share.errorClass", + "version": "1.3.4" } }, "labelPosition": { @@ -90,7 +91,8 @@ }, "tags": { "description": "Label class name", - "localKey": "API.form.global.props.form.share.labelClass" + "localKey": "API.form.global.props.form.share.labelClass", + "version": "1.3.4" } }, "formItemStyle": { @@ -112,7 +114,8 @@ }, "tags": { "description": "Form item class", - "localKey": "API.form.global.props.form.share.formItemClass" + "localKey": "API.form.global.props.form.share.formItemClass", + "version": "1.3.4" } }, "trigger": { @@ -139,6 +142,18 @@ "description": "Form item content style, supports object nesting writing method" } }, + "contentClassName": { + "defaultValue": null, + "name": "contentClassName", + "type": { + "name": "string" + }, + "tags": { + "description": "Content area style class name", + "localKey": "API.form.global.props.form.share.contentClass", + "version": "1.3.4" + } + }, "fullWidth": { "defaultValue": { "value": "false" diff --git a/.dumi/metadata/apis/docs_apiDemos_useFormReturnType.json b/.dumi/metadata/apis/docs_apiDemos_useFormReturnType.json index 6b204dd..9846173 100644 --- a/.dumi/metadata/apis/docs_apiDemos_useFormReturnType.json +++ b/.dumi/metadata/apis/docs_apiDemos_useFormReturnType.json @@ -51,7 +51,7 @@ "defaultValue": null, "name": "setState", "type": { - "name": "() => Dispatch" + "name": "() => void" }, "tags": { "localKey": "API.useForm.setState.desc", diff --git a/CHANGELOG.md b/CHANGELOG.md index f17a2fb..a08a82d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [1.3.5](https://github.com/easy-form/react-form-simple/compare/v1.3.4...v1.3.5) (2023-12-26) + +### Bug Fixes + +- fix the bug that prompts setState() method type incompatibility when using type UseFormReturnType ([2386dc0](https://github.com/easy-form/react-form-simple/commit/2386dc01ef693b78c3f359836419e1d69a3a1422)) +- Fixed model type prompt error bug when using useWatch ([2801509](https://github.com/easy-form/react-form-simple/commit/2801509bd1c8b68e3d188cd1240e65d1828671fd)) + +### Features + +- Optimize the release of memory resources after destruction when using useForm ([360f00b](https://github.com/easy-form/react-form-simple/commit/360f00b6ec1cc13872fab65a9ad3ff7edafcfa3b)) + ## [1.3.4](https://github.com/easy-form/react-form-simple/compare/v1.3.3...v1.3.4) (2023-12-25) ### Bug Fixes diff --git a/docs/demos/_controller.tsx b/docs/demos/_controller.tsx index a5784b0..762e871 100644 --- a/docs/demos/_controller.tsx +++ b/docs/demos/_controller.tsx @@ -1,10 +1,12 @@ import Button from '@components/Button'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { useForm } from 'react-form-simple'; export default function App() { const { render, model } = useForm({ name: 'name' }); + const [modelState, setModelState] = useState(''); + const renderName = render('name')(); useEffect(() => { @@ -13,11 +15,12 @@ export default function App() { }, 2000); }, []); - const onSubmit = () => void console.log(model); + const onSubmit = () => setModelState(JSON.stringify(model)); return ( <> {renderName} + {modelState} ); diff --git a/docs/demos/_example.tsx b/docs/demos/_example.tsx index 9f56ae2..ee2e8a5 100644 --- a/docs/demos/_example.tsx +++ b/docs/demos/_example.tsx @@ -1,5 +1,5 @@ import Button from '@components/Button'; -import React from 'react'; +import React, { useState } from 'react'; import { useForm } from 'react-form-simple'; export default function App() { @@ -7,17 +7,20 @@ export default function App() { name: '', age: '', }); + const [modelState, setModelState] = useState(''); + const renderName = render('name')(); const renderAge = render('age')(); const renderSubmit = ( - + ); return ( <> {renderName} {renderAge} + {modelState} {renderSubmit} ); diff --git a/docs/demos/_watch.tsx b/docs/demos/_watch.tsx index aee2bed..2dca542 100644 --- a/docs/demos/_watch.tsx +++ b/docs/demos/_watch.tsx @@ -8,7 +8,7 @@ export default function App() { const renderAge = render('age')(); useWatch( - ({ model }) => [model?.name, model?.age], + ({ model }) => [model.name, model.age], (value, preValue) => { console.log({ value, preValue }); }, diff --git a/package.json b/package.json index 6eaf1c9..93c2cfe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-form-simple", - "version": "1.3.4", + "version": "1.3.5", "description": "A form library for quickly controlling react form input", "keywords": [ "react", diff --git a/src/types/form.ts b/src/types/form.ts index 89d3484..3dc0aa8 100644 --- a/src/types/form.ts +++ b/src/types/form.ts @@ -327,8 +327,10 @@ export namespace GlobalProps { contentStyle?: CSSInterpolation; /** * @description Content area style class name + * @localKey API.form.global.props.form.share.contentClass + * @version 1.3.4 */ - contentClassName?: string + contentClassName?: string; /** * @localKey API.form.global.props.form.share.fullWidth * @description Whether the width of the form item fills the entire row @@ -374,6 +376,7 @@ export namespace GlobalProps { /** * @description Form container class name. * @localKey API.form.global.props.form.formClass + * @version 1.3.4 */ formClassName?: string; /** diff --git a/src/types/use.ts b/src/types/use.ts index 8d9f81e..89cc305 100644 --- a/src/types/use.ts +++ b/src/types/use.ts @@ -85,7 +85,7 @@ export namespace UseFormNamespace { * @description Manually re-render the view. If you need to re-render the view externally, you can call setState to re-render the current component tree. * @resetType Function */ - setState: () => React.Dispatch>; + setState: () => void; } & Apis.FormApis & Pick; } diff --git a/src/use/useController.ts b/src/use/useController.ts index 995384e..584750a 100644 --- a/src/use/useController.ts +++ b/src/use/useController.ts @@ -5,9 +5,18 @@ export function useController>(obj: T): T { const [, setState] = useState({}); const proxyStateRef = useRef(obj); - return observer(proxyStateRef.current, () => { - setState({}); - }); + const { proxyMap, rawMap } = useRef({ + proxyMap: new WeakMap(), + rawMap: new WeakMap(), + }).current; + + return observer( + proxyStateRef.current, + () => { + setState({}); + }, + { proxyMap, rawMap }, + ); } export default useController; diff --git a/src/use/useForm.ts b/src/use/useForm.ts index 30d7872..623ba64 100644 --- a/src/use/useForm.ts +++ b/src/use/useForm.ts @@ -10,7 +10,7 @@ import { usePrivateSubscribe } from './useSubscribe'; import { usePrivateWatch } from './useWatch'; const useForm = >( - model?: T, + model: T, config?: UseFormNamespace.ShareConfig, ) => { const proxyTarget = useRef(model || {}); @@ -27,6 +27,11 @@ const useForm = >( [], ); + const createObserverMap = useRef({ + proxyMap: new WeakMap(), + rawMap: new WeakMap(), + }).current; + const proxymodel = createObserverForm( proxyTarget.current as T, ({ path, value }) => { @@ -36,6 +41,7 @@ const useForm = >( }, { path: [], + ...createObserverMap, }, ); @@ -68,6 +74,7 @@ const useForm = >( useWatch, setState: useFormExtraApis.setState, ...overlayApis, + ...createObserverMap, }; }; diff --git a/src/utils/controller.ts b/src/utils/controller.ts index f9b6198..f88b400 100644 --- a/src/utils/controller.ts +++ b/src/utils/controller.ts @@ -6,14 +6,21 @@ import { isObject, isObjectOrArray } from './util'; export const proxyMap = new WeakMap(); export const rawMap = new WeakMap(); +const _proxyMap = proxyMap; +const _rawMap = rawMap; + const proxyPolyfill = ProxyPolyfillBuilder(); const Proxys = window.Proxy || proxyPolyfill; -export type ObserverOptions = { path?: string[] }; +export type ObserverOptions = { + path?: string[]; + proxyMap?: WeakMap; + rawMap?: WeakMap; +}; export type ObserverCb = { path: string; value: any }; -export const toTarget = (proxy: any) => rawMap.get(proxy); +export const toTarget = (proxy: any) => cloneDeep(proxy); export const replaceTarget = ( proxy: any, @@ -80,6 +87,7 @@ export const observer = ( cb?: (args: ObserverCb) => void, options?: ObserverOptions, ): T => { + const { path = [], rawMap = _rawMap, proxyMap = _proxyMap } = options || {}; const existingProxy = proxyMap.get(initialVal); if (existingProxy) { return existingProxy; @@ -89,8 +97,6 @@ export const observer = ( return initialVal; } - const { path = [] } = options || {}; - const proxy = new Proxys(initialVal, { get(target, key, receiver) { const ret = Reflect.get(target, key, receiver);