
规则:incompatible-library
incompatible-library
验证是否使用了与记忆化(手动或自动)不兼容的库。
规则详情 {/rule-details/}
某些库使用了 React 不支持的编程模式。当 linter 从已知列表中检测到这些 API 的使用时,会在此规则下标记它们。这意味着 React Compiler 可以自动跳过使用这些不兼容 API 的组件,以避免破坏你的应用。
js
// 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 记忆化规则被完整记录之前设计的。它们在当时做出了正确的选择,以优化符合人体工学的方式,在应用状态变化时保持组件适度的响应性。虽然这些旧模式曾经可行,但我们后来发现它与 React 的编程模型不兼容。我们将继续与库作者合作,将这些库迁移为遵循 React 规则(Rules of React)的编程模式。
设计遵循 Rules of React 的 API {/designing-apis-that-follow-the-rules-of-react/}
在设计库 API 或 hook 时,需要考虑的一个问题是,调用该 API 是否可以安全地使用 useMemo 进行记忆化。如果不能,那么手动记忆化和 React Compiler 记忆化都会破坏用户的代码。
例如,其中一种不兼容模式是“内部可变性”(interior mutability)。内部可变性是指一个对象或函数即使引用保持不变,也会随时间保持自身隐藏状态并发生变化。可以把它想象成一个外面看起来一样,但内部会悄悄重排内容的盒子。React 无法判断任何东西发生了变化,因为它只检查你是否传入了一个不同的盒子,而不检查盒子里面是什么。这会破坏记忆化,因为 React 依赖外层对象(或函数)在其值的一部分发生变化时发生变化。
作为一个经验法则,在设计 React API 时,请思考 useMemo 是否会破坏它:
js
function Component() {
const { someFunction } = useLibrary();
// it should always be safe to memoize functions like this
const result = useMemo(() => someFunction(), [someFunction]);
}
相反,请设计返回不可变状态并使用显式更新函数的 API:
js
// ✅ 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/}
本规则的错误代码示例:
js
// ❌ 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} />;
}
陷阱:MobX {/mobx/}
MobX 模式(如 observer)也会破坏记忆化假设,但 linter 目前尚未检测到它们。如果你依赖 MobX 并发现你的应用无法与 React Compiler 配合使用,你可能需要使用 "use no memo" 指令。
js
// ❌ MobX `observer`
const Component = observer(() => {
const [timer] = useState(() => new Timer());
return <span>Seconds passed: {timer.secondsPassed}</span>;
});
有效用法 {/valid/}
本规则的正确代码示例:
js
// ✅ 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 记忆化模型兼容的替代 API。如果 linter 没有自动跳过这些调用这些 API 的组件或 hooks,请提交 issue,以便我们将其添加到 linter 中。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
