From 6aa5e8a7aa3aa33541279c010acac6624ccb562e Mon Sep 17 00:00:00 2001 From: Marton Sari Date: Sun, 15 Jan 2023 05:37:09 +0100 Subject: [PATCH] feat(react/utils): Add useProxy() hook (#626) * Add useProxy() * Run prettier * add entry point and so on * Added important info to the jsdoc * deprecate useProxy macro Co-authored-by: daishi --- package.json | 42 +++++++------------------------------ rollup.config.js | 2 ++ src/macro.ts | 6 ++++++ src/macro/vite.ts | 6 ++++++ src/react-utils.ts | 1 + src/react-utils/useProxy.ts | 40 +++++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 src/react-utils.ts create mode 100644 src/react-utils/useProxy.ts diff --git a/package.json b/package.json index 69cfe519..e131e1dc 100644 --- a/package.json +++ b/package.json @@ -26,41 +26,14 @@ "module": "./esm/index.js", "default": "./index.js" }, - "./vanilla": { + "./*": { "import": { - "types": "./esm/vanilla.d.mts", - "default": "./esm/vanilla.mjs" + "types": "./esm/*.d.mts", + "default": "./esm/*.mjs" }, - "types": "./vanilla.d.ts", - "module": "./esm/vanilla.js", - "default": "./vanilla.js" - }, - "./utils": { - "import": { - "types": "./esm/utils.d.mts", - "default": "./esm/utils.mjs" - }, - "types": "./utils.d.ts", - "module": "./esm/utils.js", - "default": "./utils.js" - }, - "./macro": { - "import": { - "types": "./esm/macro.d.mts", - "default": "./esm/macro.mjs" - }, - "types": "./macro.d.ts", - "module": "./esm/macro.js", - "default": "./macro.js" - }, - "./macro/vite": { - "import": { - "types": "./esm/macro/vite.d.mts", - "default": "./esm/macro/vite.mjs" - }, - "types": "./esm/macro/vite.d.ts", - "module": "./esm/macro/vite.js", - "default": "./macro/vite.js" + "types": "./*.d.ts", + "module": "./esm/*.js", + "default": "./*.js" } }, "files": [ @@ -74,6 +47,7 @@ "build:base": "rollup -c", "build:vanilla": "rollup -c --config-vanilla", "build:utils": "rollup -c --config-utils", + "build:react-utils": "rollup -c --config-react-utils", "build:macro": "rollup -c --config-macro", "build:macro-vite": "rollup -c --config-macro_vite", "postbuild": "yarn copy && yarn patch-macro-vite && yarn patch-ts3.4 && yarn patch-esm-ts", @@ -92,7 +66,7 @@ "patch-esm-ts": "node -e \"require('shelljs').find('dist/esm/**/*.d.ts').forEach(f=>require('fs').copyFileSync(f,f.replace(/\\.ts$/,'.mts')))\"; shx sed -i \"s/ from '(\\..*)';$/ from '\\$1.mjs';/\" 'dist/esm/**/*.d.mts'; shx sed -i \"s/^declare module '(\\..*)'/declare module '\\$1.mjs'/\" 'dist/esm/**/*.d.mts'" }, "engines": { - "node": ">=12.7.0" + "node": ">=12.20.0" }, "prettier": { "semi": false, diff --git a/rollup.config.js b/rollup.config.js index edd72e28..9e5163be 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -59,6 +59,7 @@ function createESMConfig(input, output) { entries: { './vanilla': 'valtio/vanilla', '../vanilla': 'valtio/vanilla', + '../index': 'valtio', }, }), resolve({ extensions }), @@ -86,6 +87,7 @@ function createCommonJSConfig(input, output) { entries: { './vanilla': 'valtio/vanilla', '../vanilla': 'valtio/vanilla', + '../index': 'valtio', }, }), resolve({ extensions }), diff --git a/src/macro.ts b/src/macro.ts index 9397c688..118c4422 100644 --- a/src/macro.ts +++ b/src/macro.ts @@ -6,6 +6,9 @@ import * as t from '@babel/types' import { MacroError, createMacro } from 'babel-plugin-macros' const macro = ({ references }: any) => { + if (__DEV__) { + console.warn('[DEPRECATED] Use useProxy hook instead.') + } references.useProxy?.forEach((path: NodePath) => { const hook = addNamed(path, 'useSnapshot', 'valtio') const proxy = (path.parentPath?.get('arguments.0') as any)?.node @@ -39,6 +42,9 @@ const macro = ({ references }: any) => { }) } +/** + * @deprecated Use useProxy hook instead. + */ export declare function useProxy(proxyObject: T): void export default createMacro(macro, { configName: 'valtio' }) diff --git a/src/macro/vite.ts b/src/macro/vite.ts index 1eb17947..29eb2100 100644 --- a/src/macro/vite.ts +++ b/src/macro/vite.ts @@ -52,6 +52,9 @@ export const valtioMacro = defineMacro(`useProxy`) }) export function provideValtioMacro() { + if (__DEV__) { + console.warn('[DEPRECATED] Use useProxy hook instead.') + } return defineMacroProvider({ id: 'valtio/macro', exports: { @@ -62,6 +65,9 @@ export function provideValtioMacro() { }) } +/** + * @deprecated Use useProxy hook instead. + */ const macroPlugin = createMacroPlugin({}).use(provideValtioMacro()) export default macroPlugin diff --git a/src/react-utils.ts b/src/react-utils.ts new file mode 100644 index 00000000..351a7628 --- /dev/null +++ b/src/react-utils.ts @@ -0,0 +1 @@ +export { useProxy } from './react-utils/useProxy' diff --git a/src/react-utils/useProxy.ts b/src/react-utils/useProxy.ts new file mode 100644 index 00000000..5f2386c6 --- /dev/null +++ b/src/react-utils/useProxy.ts @@ -0,0 +1,40 @@ +import { useLayoutEffect } from 'react' +import { useSnapshot } from '../index' + +/** + * useProxy + * + * Takes a proxy and returns a new proxy which you can use in both react render + * and in callbacks. The root reference is replaced on every render, but the + * keys (and subkeys) below it are stable until they're intentionally mutated. + * For the best ergonomics, you can export a custom hook from your store, so you + * don't have to figure out a separate name for the hook reference. E.g.: + * + * export const store = proxy(initialState) + * export const useStore = () => useProxy(store) + * // in the component file: + * function Cmp() { + * const store = useStore() + * return + * } + * + * @param proxy + * @returns A new proxy which you can use in the render as well as in callbacks. + */ +export function useProxy(proxy: T): T { + const snapshot = useSnapshot(proxy) as T + + let isRendering = true + + useLayoutEffect(() => { + // This is an intentional hack + // eslint-disable-next-line react-hooks/exhaustive-deps + isRendering = false + }) + + return new Proxy(proxy, { + get(target, prop) { + return isRendering ? snapshot[prop as keyof T] : target[prop as keyof T] + }, + }) +}