Ref validation allows passing refs as props

Updates ValidateNoRefAccessInRender to allow passing refs to JSX, but continue 
disallowing passing ref values (so `ref` is okay but not `ref.current`)
This commit is contained in:
Joe Savona
2023-06-20 10:11:56 -07:00
parent a9868cc2b1
commit 4a36b83796
5 changed files with 70 additions and 3 deletions
@@ -49,10 +49,18 @@ export function validateNoRefAccessInRender(fn: HIRFunction): void {
// for these instructions so they ensure we have a complete analysis.
break;
}
case "JsxExpression": {
// It's okay to pass refs to JSX, but not ref *values*
for (const operand of eachInstructionValueOperand(instr.value)) {
validateNonRefValue(error, operand);
}
break;
}
case "FunctionExpression": {
// For now we assume *all* function expressions are safe, eventually we can
// be more precise and disallow ref access in functions that may be called
// during render
// functions are allowed to capture refs, so long as the function is not called
// during render. see AnalyzeFunctions for how we ensure that functions which
// capture refs get assigned a mutable range so we know here whether the function
// is called or not
const mutableRange = instr.lvalue.identifier.mutableRange;
if (mutableRange.end > mutableRange.start + 1) {
for (const operand of eachInstructionValueOperand(instr.value)) {
@@ -0,0 +1,32 @@
## Input
```javascript
function Component(props) {
const ref = useRef(null);
return <Foo ref={ref} />;
}
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(2);
const ref = useRef(null);
const c_0 = $[0] !== ref;
let t0;
if (c_0) {
t0 = <Foo ref={ref} />;
$[0] = ref;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
```
@@ -0,0 +1,4 @@
function Component(props) {
const ref = useRef(null);
return <Foo ref={ref} />;
}
@@ -0,0 +1,19 @@
## Input
```javascript
function Component(props) {
const ref = useRef(null);
return <Foo ref={ref.current} />;
}
```
## Error
```
[ReactForget] InvalidInput: Ref values (the `current` property) may not be accessed during render. Cannot access ref value at freeze $20:TObject<BuiltInRefValue> (3:3)
```
@@ -0,0 +1,4 @@
function Component(props) {
const ref = useRef(null);
return <Foo ref={ref.current} />;
}