我正在尝试创建一个本地共享文件夹/工作区/包,以使用 npm 工作区在 monorepo 中的项目之间共享代码,并且它在 vite 开发模式下工作,但当我使用 vite / rollup 构建和预览时则不起作用。
TypeError: Cannot read properties of null (reading 'useState')
at react_production_min.useState (index.js:85289:286)
at useDebounceValue (index.js:86924:53)
at AppContainer (index.js:86942:36)
这是我的文件夹结构:
my-app/
├─ node_modules/
├─ packages/
│ ├─ shared/
│ ├─ app/
├─ package.json
这是我的根package.json:
{
"name": "frontends",
"version": "1.0.0",
"description": "Our frontends",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"workspaces": [
"packages/*"
],
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"autoprefixer": "10.4.17",
"postcss": "8.4.35",
"tailwindcss": "3.4.1"
}
}
这是我共享的package.json
{
"name": "@myscope/shared",
"version": "1.0.0",
"description": "Shared components, libraries and utils for frontend projects",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"type": "module",
"author": "",
"license": "ISC",
"peerDependencies": {
"i18next": "23.11.3",
"oidc-client-ts": "2.4.0",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "14.2.1",
"i18next": "23.11.3",
"oidc-client-ts": "2.4.0",
"react": "18.2.0",
"react-dom": "18.2.0"
}
}
我在共享中有一个 React hook:
import React from "react";
/**
* Debounced value update, e.g. to trigger search after a user stops typing
* @param value
* @param delay
*/
export default function useDebounceValue(value: string, delay: number) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = React.useState(value);
React.useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value]);
return debouncedValue;
}
这是应用程序vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import { htmlInjectionPlugin } from "vite-plugin-html-injection";
// https://vitejs.dev/config/
export default defineConfig({
preview: {
port: 5174,
},
server: {
port: 5174,
},
plugins: [
react(),
htmlInjectionPlugin({
injections: [
{
name: "Global Config",
path: "./public/config.js",
type: "js",
injectTo: "head",
},
],
}),
],
build: {
assetsDir: "public/assets",
outDir: "./build",
minify: false,
target: "esnext",
assetsInlineLimit: 8192,
rollupOptions: {
output: {
entryFileNames: `assets/[name].js`,
chunkFileNames: `assets/[name].js`,
assetFileNames: `assets/[name].[ext]`,
},
},
},
base: "./",
});
在应用程序内部,我有一个 appContainer.tsx,我尝试在其中使用
useDebounceValue
(仅作为测试)
import { useEffect } from "react";
import { useSelector } from "react-redux";
import { useDebounceValue } from "@myscope/shared/react/hooks";
import { MenuItem } from "../core/models/menu";
import { RootState } from "../core/state/dependencies";
export const AppContainer = () => {
const activeMenu: MenuItem | null | undefined = useSelector(
(state: RootState) => state.menu.activeMenu,
);
const debouncedTest = useDebounceValue(activeMenu?.title, 500);
useEffect(() => {
console.info(debouncedTest);
}, [debouncedTest]);
return (
<div>Test</div>
);
};
在 vite dev 中运行良好,但如果我执行 vite build && vite Preview,它会失败并出现来自顶部的 null 错误。
如果我检查 rollup 构建的 index.js,我会发现“应用程序”中所有对 React 的使用都使用以下 React 引用:
var reactExports$1 = react$1.exports;
const React$1 = /*@__PURE__*/getDefaultExportFromCjs(reactExports$1);
但是 useDebounceValue 中的那个似乎有它自己的反应引用,最终为空。
var reactExports = react.exports;
const React = /*@__PURE__*/getDefaultExportFromCjs(reactExports);
/**
* @license React
...
function useDebounceValue(value, delay) {
const [debouncedValue, setDebouncedValue] = React.useState(value);
React.useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value]);
return debouncedValue;
}
我在这里做错了什么?
问题是我在其中一个包含我没有想到的 React deps 的包中有一个旧的 package-lock.json 。删除它,并确保没有任何包作为依赖项做出反应(我只将它放在根 package.json 中)使其工作。