Custom Rules
No createRef
Disallow React.createRef() in favor of useRef.
Rule Code
Copy and paste this into your eslint.config.ts:
import eslintJs from "@eslint/js";
import { defineConfig as defineReactConfig, merge } from "@eslint-react/kit";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";
export default defineConfig(
{
files: ["**/*.{ts,tsx}"],
extends: [
eslintJs.configs.recommended,
tseslint.configs.recommended,
defineReactConfig(
{
name: "no-create-ref",
make: (ctx, kit) => {
const isCreateRefCall = kit.is.reactAPICall("createRef");
return {
CallExpression(node) {
if (isCreateRefCall(ctx, node)) {
ctx.report({
node,
message: "Don't use 'createRef'. Use the 'useRef' hook instead.",
});
}
},
};
},
},
),
],
},
);Examples
❌ Invalid
import React from "react";
class MyComponent extends React.Component {
ref = React.createRef<HTMLDivElement>();
render() {
return <div ref={this.ref}>Hello</div>;
}
}import { createRef } from "react";
const ref = createRef<HTMLInputElement>();✅ Valid
import { useRef } from "react";
function MyComponent() {
const ref = useRef<HTMLDivElement>(null);
return <div ref={ref}>Hello</div>;
}How It Works
This rule uses kit.is.reactAPICall("createRef") to create a predicate that identifies calls to React.createRef() (including bare createRef() imports). Unlike collector-based rules, this rule works as a simple AST visitor — it checks every CallExpression node directly, with no need for a collector or merge.
kit.is.reactAPICall is a factory: you pass any React API name and get back a predicate that handles all import styles (namespace import, named import, etc.). For common APIs, pre-built predicates are also available directly on kit.is — for example kit.is.memoCall, kit.is.forwardRefCall, kit.is.createElementCall.
Customization Ideas
- Extend to also ban
React.createRefas an identifier reference (not just calls), usingkit.is.reactAPI("createRef") - Add auto-fix to convert
createRef()touseRef(null)inside function components - Ban other legacy APIs like
createElementusing the pre-builtkit.is.createElementCallpredicate