我遇到了一些非常奇怪的行为。我有一个更大的项目,但为了演示的目的,下面是简单的Next。JS应用程序就足够了。
复制步骤:
-
创建一个简单的Next。JS项目:
npx create-next-app my-next-app --ts
-
将以下2个文件添加到项目中:
// ./componens/logs.ts
export function createLogger(options: { name: string }) {
const logIdObj = { logId: 0 };
function vivify(o: { logId: number }) {
let n = 0;
Object.defineProperty(o, 'logId', {
get: () => {
console.warn(`Getting logId for logger ${options.name}: ${n}`);
return n;
},
set: (v: number) => {
console.warn(`Setting logId for logger ${options.name}: ${v}`);
n = v;
},
});
}
vivify(logIdObj);
return (message: string) => {
logIdObj.logId += 1;
console.log(`${logIdObj.logId}. ${message}`);
};
}
// ./componens/Chat.tsx
import { useEffect } from 'react';
import { createLogger } from './logs';
const log = createLogger({ name: 'Chat' });
export default function Chat(): JSX.Element {
log('render');
useEffect(() => {
log('useEffect');
}, []);
return <div>Some content</div>;
}
-
修改主页面文件
./pages/index.tsx
这样地:
import type { NextPage } from 'next'
import Chat from '../components/Chat'
const Home: NextPage = () => {
return <>
<Chat />
<h1>Welcome</h1>
</>
}
export default Home
-
以开发模式运行项目:
npm run dev
-
打开浏览器,导航到
localhost:3000
看看您将在控制台中得到什么:
如中所示
./componens/logs.ts
对的访问
logId
的属性
logIdObj
对象被有意地包装在getter-setter拦截器中,以记录对它的任何类型的访问,但根据日志,值在未被访问的情况下被更改。
这是我的环境:
Distributor ID: Debian
Description: Debian GNU/Linux 10 (buster)
Release: 10
Codename: buster
node: v14.17.0
npm: 7.22.0
和我的
package.json
:
{
"name": "my-next-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "11.1.2",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@types/react": "17.0.30",
"eslint": "7.32.0",
"eslint-config-next": "11.1.2",
"typescript": "4.4.4"
}
}
我想这可能与内部的Next有关。JS逻辑,但无论如何都不应该这样工作。
一如既往,我们将不胜感激。
使现代化
:
虽然是第一次回复(感谢
Ben
)对问题的原因没有给出明确的答案,它给出了可能出错的线索。所以我修改了
./componens/logs.ts
这样地:
const allLogs = [] as { message: string, logId: number, time: number }[];
if (typeof window !== 'undefined') {
// @ts-ignore
window.allLogs = allLogs;
}
export function createLogger(options: { name: string }) {
let logId = 0;
return (message: string) => {
logId += 1;
allLogs.push({ message, logId, time: Date.now() });
console.log(`${logId}. ${message}`);
};
}
现在我的结果是这样的:
现在我们可以清楚地看到,渲染实际上发生了两次
console.log()
并不总是产生实际的日志。尽管如此,原因尚不清楚。
有什么解释吗?