验证是否使用了与 memoization 不兼容的库(手动或自动)。
¥Validates against usage of libraries which are incompatible with memoization (manual or automatic).
规则详情
¥Rule Details
某些库使用了 React 不支持的模式。当 linter 从 已知列表 检测到这些 API 的使用情况时,它会根据此规则对其进行标记。这意味着 React Compiler 可以自动跳过使用这些不兼容 API 的组件,以避免破坏你的应用。
¥Some libraries use patterns that aren’t supported by React. When the linter detects usages of these APIs from a known list, it flags them under this rule. This means that React Compiler can automatically skip over components that use these incompatible APIs, in order to avoid breaking your app.
// Example of how memoization breaks with these libraries
function Form() {
const { watch } = useForm();
// ❌ This value will never update, even when 'name' field changes
const name = useMemo(() => watch('name'), [watch]);
return <div>Name: {name}</div>; // UI appears "frozen"
}
React Compiler 会根据 React 规则自动记忆值。如果手动 useMemo
出现问题,它也会破坏编译器的自动优化。此规则有助于识别这些有问题的模式。
¥React Compiler automatically memoizes values following the Rules of React. If something breaks with manual useMemo
, it will also break the compiler’s automatic optimization. This rule helps identify these problematic patterns.
深入研究
¥Designing APIs that follow the Rules of React
在设计库 API 或钩子时需要考虑的一个问题是,调用 API 是否可以通过 useMemo
安全地进行记忆。如果无法激活,那么手动和 React 编译器的记忆功能都会破坏用户的代码。
¥One question to think about when designing a library API or hook is whether calling the API can be safely memoized with useMemo
. If it can’t, then both manual and React Compiler memoizations will break your user’s code.
例如,“内部可变性” 就是这样一种不兼容的模式。内部可变性是指对象或函数保持其自身的隐藏状态,该状态会随时间变化,即使对它的引用保持不变。可以把它想象成一个外表相同但内容却秘密重新排列的盒子。React 无法识别任何更改,因为它只会检查你是否输入了不同的框,而不会检查框内的内容。这会破坏记忆机制,因为 React 依赖于外部对象(或函数)在其部分值发生变化时进行更改。
¥For example, one such incompatible pattern is “interior mutability”. Interior mutability is when an object or function keeps its own hidden state that changes over time, even though the reference to it stays the same. Think of it like a box that looks the same on the outside but secretly rearranges its contents. React can’t tell anything changed because it only checks if you gave it a different box, not what’s inside. This breaks memoization, since React relies on the outer object (or function) changing if part of its value has changed.
根据经验,在设计 React API 时,请考虑 useMemo
是否会破坏它:
¥As a rule of thumb, when designing React APIs, think about whether useMemo
would break it:
function Component() {
const { someFunction } = useLibrary();
// it should always be safe to memoize functions like this
const result = useMemo(() => someFunction(), [someFunction]);
}
相反,设计返回不可变状态并使用显式更新函数的 API:
¥Instead, design APIs that return immutable state and use explicit update functions:
// ✅ Good: Return immutable state that changes reference when updated
function Component() {
const { field, updateField } = useLibrary();
// this is always safe to memo
const greeting = useMemo(() => `Hello, ${field.name}!`, [field.name]);
return (
<div>
<input
value={field.name}
onChange={(e) => updateField('name', e.target.value)}
/>
<p>{greeting}</p>
</div>
);
}
无效
¥Invalid
此规则的错误代码示例:
¥Examples of incorrect code for this rule:
// ❌ react-hook-form `watch`
function Component() {
const {watch} = useForm();
const value = watch('field'); // Interior mutability
return <div>{value}</div>;
}
// ❌ TanStack Table `useReactTable`
function Component({data}) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
// table instance uses interior mutability
return <Table table={table} />;
}
有效
¥Valid
此规则的正确代码示例:
¥Examples of correct code for this rule:
// ✅ For react-hook-form, use `useWatch`:
function Component() {
const {register, control} = useForm();
const watchedValue = useWatch({
control,
name: 'field'
});
return (
<>
<input {...register('field')} />
<div>Current value: {watchedValue}</div>
</>
);
}
其他一些库目前还没有与 React 的 memoization 模型兼容的替代 API。如果 linter 没有自动跳过调用这些 API 的组件或钩子,请使用 提交问题,以便我们将其添加到 linter 中。
¥Some other libraries do not yet have alternative APIs that are compatible with React’s memoization model. If the linter doesn’t automatically skip over your components or hooks that call these APIs, please file an issue so we can add it to the linter.