codemask-labs/stan-js

Hooks must be the same function on every render

Closed this issue ยท 5 comments

When using stan paired with the react-compiler ESLint rules as per documentation, the scoped store seems to violate one of the rules of hooks, not sure if this is just an edge case

image
image

import { createScopedStore } from "stan-js";
import { storage } from "stan-js/storage";

const { StoreProvider, useScopedStore, withStore } = createScopedStore({
    isBottomBarExpanded: storage(false),
});

I guess a quick fix would be to change notation to either:

const { useStore } = useScopedStore();
const { isBottomBarExpanded } = useStore();

or

const { isBottomBarExpanded } = useScopedStore().useStore();

But I'm just guessing since my eslint wasn't throwing that error. Can u share your eslint config and versions of eslint and eslint-plugin-react-compiler that you're using? ๐Ÿ™

"devDependencies": {
        "@typescript-eslint/eslint-plugin": "^7.14.1",
        "@typescript-eslint/parser": "^7.14.1",
        "eslint": "^8.57.0",
        "eslint-config-prettier": "^9.1.0",
        "eslint-plugin-prettier": "^5.1.3",
        "eslint-plugin-react-compiler": "0.0.0-experimental-c8b3f72-20240517",
        "typescript": "^5.5.2",
    },
/** @type {import('eslint').Linter.Config} */
const config = {
    extends: ["plugin:@typescript-eslint/recommended-type-checked", "plugin:@typescript-eslint/stylistic-type-checked", "plugin:prettier/recommended"],
    root: true,
    env: { es2022: true, node: true },
    parser: "@typescript-eslint/parser",
    parserOptions: {
        tsconfigRootDir: __dirname,
        project: ["./tsconfig.json", "./packages/*/tsconfig.json"],
    },
    overrides: [
        {
            files: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.mjs"],
            plugins: ["@typescript-eslint", "react-compiler"],
            rules: { "react-compiler/react-compiler": "error" },
        }
    ]
};

module.exports = config;

I guess a quick fix would be to change notation to either:

const { useStore } = useScopedStore();
const { isBottomBarExpanded } = useStore();

or

const { isBottomBarExpanded } = useScopedStore().useStore();

eslint catches both syntaxes and present the same error message

image

image

Thanks @rortan134 for finding this issue, indeed we're technically breaking one of the hooks laws. stan-js works with react compiler without any issue but eslint will throw the error. I've just created PR with fix, we will release stan-js@1.4.1 today and syntax will be changed following way:

// yourstorefile.ts
import { createScopedStore } from "stan-js";
import { storage } from "stan-js/storage";

const { StoreProvider, useStore, withStore } = createScopedStore({
    isBottomBarExpanded: storage(false),
});
// usage.tsx
const { isBottomBarExpanded } = useStore()

eslint-plugin-react-compiler is now fine with it ๐Ÿ˜„

๐ŸŽ‰ This issue has been resolved in version 1.4.1 ๐ŸŽ‰

The release is available on:

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€