Getting eslint errors writing a simple server component with server action:
// /app/search/page.tsx
export default function Search() {
async function updateResults(formData: FormData) {
"use server";
await new Promise((resolve) => setTimeout(resolve, 150));
console.log("input value => ", formData.get("me"));
revalidatePath("/search");
}
return (
<>
<form action={updateResults}> {/* eslint errors here */}
<input name="me" type="text" />
<button type="submit">Update</button>
</form>
</>
)
}
Get a couple eslint errors on the <form action={updateResults}>
JSX props should not use functions eslint(react/jsx-no-bind)Promise-returning function provided to attribute where a void return was expected. eslint(@typescript-eslint/no-misused-promises)What am I doing wrong? Can we call server actions from RSC or should the form be a client component only?
I'm on next 14 with eslint 8.36
My package.json:
"dependencies": {
"@next/third-parties": "^14.0.4",
"i18next": "^23.0.0",
"js-cookie": "^3.0.5",
"lodash": "^4.17.21",
"next": "^14.0.3",
"next-i18next": "^15.0.0",
"next-intl": "^3.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^14.0.0",
"server-only": "^0.0.1",
"sharp": "^0.33.0"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.0.2",
"@storybook/addon-designs": "^7.0.1",
"@storybook/addon-essentials": "^7.1.0",
"@storybook/nextjs": "^7.1.0",
"@storybook/react": "^7.1.0",
"@testing-library/dom": "^9.0.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest-axe": "^3.5.5",
"@types/js-cookie": "^3.0.6",
"@types/node": "^20.8.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"eslint": "^8.36.0",
"eslint-config-mycustomconfig": "^12.1.0",
"eslint-config-next": "^13.2.4",
"eslint-config-prettier": "^8.7.0",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jest-dom": "^5.0.1",
"eslint-plugin-storybook": "^0.6.12",
"eslint-plugin-testing-library": "^5.11.0",
"i18next-browser-languagedetector": "^7.0.2",
"i18next-http-backend": "^2.2.1",
"jest": "^29.5.0",
"jest-axe": "^7.0.0",
"jest-cli": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"postcss": "^8.4.31",
"postcss-loader": "^7.1.0",
"postcss-preset-env": "^8.0.1",
"prettier": "^3.2.5",
"sass": "^1.59.3",
"sass-loader": "^13.2.0",
"storybook": "^7.1.0",
"storybook-react-i18next": "^2.0.6",
"style-loader": "^3.3.2",
"typescript": "^5.0.0"
}
eslintrc.js:
module.exports = {
root: true,
extends: [
"plugin:storybook/recommended",
// Disable ESLint code formatting rules which conflict with Prettier
"prettier",
// `next` should be extended last according to their docs
// https://nextjs.org/docs/basic-features/eslint
"next/core-web-vitals",
],
rules: {
// Next.js <Image> component is useful for optimizing images, but also requires additional
// dependencies to work in standalone mode. It may be overkill for most projects at
// Which aren't image heavy.
"@next/next/no-img-element": "off",
},
// Additional lint rules. These get layered onto the top-level rules.
overrides: [
// Lint config specific to Test files
{
files: ["tests/**"],
plugins: ["jest"],
extends: [
"plugin:jest/recommended",
"plugin:jest-dom/recommended",
"plugin:testing-library/react",
],
},
// Lint config specific to TypeScript files
{
files: "**/*.+(ts|tsx)",
parserOptions: {
// These paths need defined to support rules that require type information
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
},
extends: [
"plugin:@typescript-eslint/recommended",
// Disable vanilla ESLint rules that conflict with those in @typescript-eslint
"plugin:@typescript-eslint/eslint-recommended",
// Rules that specifically require type information
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
plugins: ["@typescript-eslint"],
rules: {
// Prevent dead code accumulation
"@typescript-eslint/no-unused-vars": "error",
// The usage of `any` defeats the purpose of typescript. Consider using `unknown` type instead instead.
"@typescript-eslint/no-explicit-any": "error",
},
},
],
settings: {
// Support projects where Next.js isn't installed in the root directory (such as a monorepo)
next: {
rootDir: __dirname,
},
},
};
I didn't really follow the next 14 eslint setup docs so there may be issues there.
You are using correctly server actions. You just have to disable the ESLint rule added by one of the extends in the overrides part of your .eslintrc.js, which makes sense in most scenarios but didn't predict server actions in React:
{
files: "**/*.+(ts|tsx)",
// ...
rules: {
//...
"@typescript-eslint/no-misused-promises": "off",
},
}
A fine grained solution is the configuring the rule like this in .eslintrc.js:
{
// ...
rules: {
// ...
"@typescript-eslint/no-misused-promises": [
"error",
{
checksVoidReturn: {
attributes: false
}
}
],
// ...
}
// ...
}
This specifically only disables checking for void returns in attributes, the place where server actions are used. Check the official typescript-eslint documenation for more for information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With