mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Infer type of ref argument
Extend type inference to infer second argument of component as a ref type
This commit is contained in:
@@ -18,7 +18,11 @@ import {
|
||||
TypeId,
|
||||
TypeVar,
|
||||
} from "../HIR/HIR";
|
||||
import { BuiltInArrayId, BuiltInObjectId } from "../HIR/ObjectShape";
|
||||
import {
|
||||
BuiltInArrayId,
|
||||
BuiltInObjectId,
|
||||
BuiltInUseRefId,
|
||||
} from "../HIR/ObjectShape";
|
||||
import { eachInstructionLValue, eachInstructionOperand } from "../HIR/visitors";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
|
||||
@@ -94,6 +98,16 @@ function equation(left: Type, right: Type): TypeEquation {
|
||||
function* generate(
|
||||
func: HIRFunction
|
||||
): Generator<TypeEquation, void, undefined> {
|
||||
if (func.env.fnType === "Component") {
|
||||
const [_, ref] = func.params;
|
||||
if (ref && ref.kind === "Identifier") {
|
||||
yield equation(ref.identifier.type, {
|
||||
kind: "Object",
|
||||
shapeId: BuiltInUseRefId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const [_, block] of func.body.blocks) {
|
||||
for (const phi of block.phis) {
|
||||
yield equation(phi.type, {
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateRefAccessDuringRender:true
|
||||
function Foo(props, ref) {
|
||||
console.log(ref.current);
|
||||
return <div>{props.bar}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ bar: "foo" }, { ref: { cuurrent: 1 } }],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
1 | // @validateRefAccessDuringRender:true
|
||||
2 | function Foo(props, ref) {
|
||||
> 3 | console.log(ref.current);
|
||||
| ^^^^^^^^^^^ [ReactForget] InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $16:TObject<BuiltInRefValue> (3:3)
|
||||
4 | return <div>{props.bar}</div>;
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// @validateRefAccessDuringRender: true
|
||||
// @validateRefAccessDuringRender:true
|
||||
function Foo(props, ref) {
|
||||
ref.current = 2;
|
||||
console.log(ref.current);
|
||||
return <div>{props.bar}</div>;
|
||||
}
|
||||
|
||||
+11
-15
@@ -25,32 +25,28 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
import { useEffect, unstable_useMemoCache as useMemoCache } from "react";
|
||||
|
||||
function Foo(props, ref) {
|
||||
const $ = useMemoCache(5);
|
||||
const $ = useMemoCache(4);
|
||||
let t0;
|
||||
if ($[0] !== ref.current) {
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
ref.current = 2;
|
||||
};
|
||||
$[0] = ref.current;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
let t1;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [];
|
||||
$[2] = t1;
|
||||
$[0] = t0;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
t0 = $[0];
|
||||
t1 = $[1];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
let t2;
|
||||
if ($[3] !== props.bar) {
|
||||
if ($[2] !== props.bar) {
|
||||
t2 = <div>{props.bar}</div>;
|
||||
$[3] = props.bar;
|
||||
$[4] = t2;
|
||||
$[2] = props.bar;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateRefAccessDuringRender: true
|
||||
function Foo(props, ref) {
|
||||
ref.current = 2;
|
||||
return <div>{props.bar}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ bar: "foo" }, { ref: { cuurrent: 1 } }],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @validateRefAccessDuringRender: true
|
||||
function Foo(props, ref) {
|
||||
const $ = useMemoCache(2);
|
||||
ref.current = 2;
|
||||
let t0;
|
||||
if ($[0] !== props.bar) {
|
||||
t0 = <div>{props.bar}</div>;
|
||||
$[0] = props.bar;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ bar: "foo" }, { ref: { cuurrent: 1 } }],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>foo</div>
|
||||
Reference in New Issue
Block a user