Skip to content

Commit

Permalink
feat(react/utils): Add useProxy() hook (#626)
Browse files Browse the repository at this point in the history
* Add useProxy()

* Run prettier

* add entry point and so on

* Added important info to the jsdoc

* deprecate useProxy macro

Co-authored-by: daishi <daishi@axlight.com>
  • Loading branch information
sarimarton and dai-shi committed Jan 15, 2023
1 parent 2fab622 commit 6aa5e8a
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 34 deletions.
42 changes: 8 additions & 34 deletions package.json
Expand Up @@ -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": [
Expand All @@ -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",
Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions rollup.config.js
Expand Up @@ -59,6 +59,7 @@ function createESMConfig(input, output) {
entries: {
'./vanilla': 'valtio/vanilla',
'../vanilla': 'valtio/vanilla',
'../index': 'valtio',
},
}),
resolve({ extensions }),
Expand Down Expand Up @@ -86,6 +87,7 @@ function createCommonJSConfig(input, output) {
entries: {
'./vanilla': 'valtio/vanilla',
'../vanilla': 'valtio/vanilla',
'../index': 'valtio',
},
}),
resolve({ extensions }),
Expand Down
6 changes: 6 additions & 0 deletions src/macro.ts
Expand Up @@ -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
Expand Down Expand Up @@ -39,6 +42,9 @@ const macro = ({ references }: any) => {
})
}

/**
* @deprecated Use useProxy hook instead.
*/
export declare function useProxy<T extends object>(proxyObject: T): void

export default createMacro(macro, { configName: 'valtio' })
6 changes: 6 additions & 0 deletions src/macro/vite.ts
Expand Up @@ -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: {
Expand All @@ -62,6 +65,9 @@ export function provideValtioMacro() {
})
}

/**
* @deprecated Use useProxy hook instead.
*/
const macroPlugin = createMacroPlugin({}).use(provideValtioMacro())

export default macroPlugin
1 change: 1 addition & 0 deletions src/react-utils.ts
@@ -0,0 +1 @@
export { useProxy } from './react-utils/useProxy'
40 changes: 40 additions & 0 deletions 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 <button onClick={() => {store.count++}}>{store.count}</button>
* }
*
* @param proxy
* @returns A new proxy which you can use in the render as well as in callbacks.
*/
export function useProxy<T extends object>(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]
},
})
}

1 comment on commit 6aa5e8a

@vercel
Copy link

@vercel vercel bot commented on 6aa5e8a Jan 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

valtio – ./

valtio-pmndrs.vercel.app
valtio.pmnd.rs
valtio-git-main-pmndrs.vercel.app
valtio.vercel.app

Please sign in to comment.