incompatible-library
Valida contra o uso de bibliotecas que são incompatíveis com a memoização (manual ou automática).
Detalhes da Regra
Algumas bibliotecas usam padrões que não são suportados pelo React. Quando o linter detecta usos dessas APIs de uma lista conhecida, ele as sinaliza sob esta regra. Isso significa que o Compilador React pode pular automaticamente componentes que usam essas APIs incompatíveis, a fim de evitar a quebra do seu aplicativo.
// Exemplo de como a memoização quebra com essas bibliotecas
function Form() {
const { watch } = useForm();
// ❌ Este valor nunca será atualizado, mesmo quando o campo 'name' mudar
const name = useMemo(() => watch('name'), [watch]);
return <div>Name: {name}</div>; // A UI parece "congelada"
}O Compilador React memoiza automaticamente valores seguindo as Regras do React. Se algo quebrar com useMemo manual, também quebrará a otimização automática do compilador. Esta regra ajuda a identificar esses padrões problemáticos.
Deep Dive
Uma pergunta a se considerar ao projetar uma API ou hook de biblioteca é se a chamada da API pode ser memoizada com segurança com useMemo. Se não puder, tanto a memoização manual quanto a do Compilador React quebrarão o código do seu usuário.
Por exemplo, um desses padrões incompatíveis é a “mutabilidade interior”. Mutabilidade interior é quando um objeto ou função mantém seu próprio estado oculto que muda ao longo do tempo, mesmo que a referência a ele permaneça a mesma. Pense nisso como uma caixa que parece a mesma por fora, mas secretamente reorganiza seu conteúdo. O React não consegue dizer que algo mudou porque ele apenas verifica se você deu a ele uma caixa diferente, não o que está dentro. Isso quebra a memoização, pois o React depende do objeto (ou função) externo mudar se parte de seu valor mudou.
Como regra geral, ao projetar APIs React, pense se useMemo a quebraria:
function Component() {
const { someFunction } = useLibrary();
// deve ser sempre seguro memoizar funções como esta
const result = useMemo(() => someFunction(), [someFunction]);
}Em vez disso, projete APIs que retornem estado imutável e usem funções de atualização explícitas:
// ✅ Bom: Retorna estado imutável que muda de referência quando atualizado
function Component() {
const { field, updateField } = useLibrary();
// isso é sempre seguro para memoizar
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>
);
}Inválido
Exemplos de código incorreto para esta regra:
// ❌ `watch` do react-hook-form
function Component() {
const {watch} = useForm();
const value = watch('field'); // Mutabilidade interior
return <div>{value}</div>;
}
// ❌ `useReactTable` da TanStack Table
function Component({data}) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
// a instância da tabela usa mutabilidade interior
return <Table table={table} />;
}Válido
Exemplos de código correto para esta regra:
// ✅ Para 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>
</>
);
}Algumas outras bibliotecas ainda não possuem APIs alternativas que sejam compatíveis com o modelo de memoização do React. Se o linter não pular automaticamente seus componentes ou hooks que chamam essas APIs, por favor, abra uma issue para que possamos adicioná-la ao linter.