Comments (9)
Idea: When accessing .current
on a variable, it must be explicitly labelled or inferred to either be a ref or a non-ref. Assignment to useRef
would automatically label it as a ref, as would wrapping it in the new macros markRef
and markNonRef
.
Triggers warning:
function App({ myRef /* is ref: unknown */ }) {
useAutoEffect(() => {
myRef.current
})
return null
}
Does not trigger warning:
function App({ myRef }) {
markRef(myRef) // is ref: true
useAutoEffect(() => {
myRef.current
})
return null
}
function App({ myRef }) {
markNonRef(myRef) // is ref: false
useAutoEffect(() => {
myRef.current
})
return null
}
function App() {
const myRef = useRef() // is ref: true
useAutoEffect(() => {
myRef.current
})
return null
}
function App({ myRef /* is ref: unknown */ }) {
const { current } = myRef
useAutoEffect(() => {
current
})
return null
}
from hooks.macro.
If the default behavior is to add the object to dependencies and show a warning, it would probably not break a lot of code.
from hooks.macro.
The algorithm
- If
.current
is accessed in the scope or child scope of an auto hook- Find its highest parent (
foo.bar.current
->foo
) - Determine status of highest parent.
- If
maybeRef
, throw error. - If
isRef
, add top parent to dependencies. - If
isNonRef
, add property access to dependencies.
- If
- Find its highest parent (
Determine status
- If defined in hook:
nonRef
- Go to component function scope
- If defined by
React.useRef
:isRef
- If defined by
React.use*
:isNonRef
- If called with
markRef
in component function scope:isRef
- If called with
markNonRef
in component function scope:isNonRef
- If defined by
- Otherwise:
maybeRef
Error message
Could not determine if ${expression} was ref or not.
Include `markRef(${topParent})` or `markNonRef(${topParent})`
in the function body to specify whether `${topParent}.*.current`
or is a React ref.
markRef/markNonRef
- For each argument:
- Assert that it's an identifier and that it is in scope
- Remove call expression
from hooks.macro.
Is it possible to have useAutoMemo()
generate a variable with a munged name and then use that variable when memoizing?
e.g.
function MyComponent({ config }) {
const __asdfanasdfjl__ = config.value;
return useMemo(() => __asdfanasdfjl__ * 2, [__asdfanasdfjl__]);
}
from hooks.macro.
@neoncube2 yeah that is the plan, the problem is that accessing a property is not pure/idempotent (think property getters) and some ordering may need to be respected.
@adrianhelvik your approach is actually very clean! I’ll look into it! (Sorry for the huge delay!)
from hooks.macro.
No worries. That's great news! 🙂
from hooks.macro.
Thanks, @yuchi. I wonder if the ordering really needs to be respected, though? My understanding is that render()
is already supposed to be pure, so it seems like we should be able to access properties as many times as we like without side effects 🙂
from hooks.macro.
@neoncube2 Yes, render functions are pure, but callbacks and effect callbacks can (and usually indeed are) impure.
from hooks.macro.
Some important things to consider is conditionals, this
-context and impure getters. This contrived example:
const [config, configure] = useState()
const ref = useAutoCallback(element => {
configure({
actions: {
click() { element.click() }
}
})
})
useAutoEffect(() => {
if (!element) return
config.actions.click()
})
return <button ref={ref}>Click me!</button>
(Train of thought)
Would break if transpiled into:
var _click = config.actions.click
useEffect(() => {
if (!element) return
_click()
}, [_click])
An alternative would be to transpile into:
var _click = config?.actions?.click
useEffect(() => {
if (!element) return
_click()
}, [_click])
But that would change the this
context, if the ref looked like this for example:
const ref = useAutoCallback(element => {
configure({
element,
click() { this.element.click() }
})
})
So the original input...
Should leave us with something like:
// ...
var _click = config?.actions?.click
useEffect(() => {
if (!element) return
_click.call(config.actions)
}, [element, _click])
// ...
Edit: Then again, I don't think supporting impure getters should be the highest priority as it complicates the implementation for minimal gain. Without support for impure getters, there will be no need to handle this
-context.
// ...
useEffect(() => {
if (!element) return
config.actions.click()
}, [element, config?.actions?.click])
// ...
from hooks.macro.
Related Issues (16)
- Extract indirect dependencies
- Do not inject setState/ref into dependencies HOT 7
- State values with unused setters are known to be static (if const)
- Memoized values with empty inputs array are known to be static
- Known static return value from react-redux hook HOT 1
- useAutoUpdateEffect HOT 2
- Not adding dynamic components to dependencies HOT 3
- Feature request: debugChangedDependencies HOT 2
- Create a debug/trace facility
- Support React 17? HOT 5
- Create an escape hatch HOT 2
- Create a generic form HOT 2
- Bail out on constants HOT 1
- Error/warn on known non-invariants
- TypeScript support HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hooks.macro.