Zan*_*aes 2 reactjs react-hooks
我正在尝试编写一个自定义 React 钩子,useLogging我想根据正在执行日志记录的组件的名称将日志消息上下文化。
例如:
const Login: React.FunctionComponent<IProps> = (props) => {
log = useLogging();
log.info("Hello!")
[...]
Run Code Online (Sandbox Code Playgroud)
应产生 [Login] Hello!
然后,我的自定义钩子需要名称Login:
export const useLogger = () => {
// "this" is undefined
const loggerName = ??????
return logManager.getLogger(loggerName);
};
Run Code Online (Sandbox Code Playgroud)
在类的上下文中,我正在寻找的是类似this.constructor.displayName. 但是,React 钩子没有this设置,我似乎找不到有关获取对功能组件上下文的引用的文档。
----
编辑:我不想传递任何参数,也不想添加一堆样板。我的目标是该useLogging()函数将在组件重构中幸存下来,而不是依赖于开发人员提供“正确”的名称。
我可以想到您可以使用的其他几种方法。Drew 在评论中建议的第一个也是最简单的一个,即简单地将日志名称作为参数传递:
const useLogger = (name: string) => {
return logManager.getLogger(name)
}
const Login: React.FC<Props> = () => {
const log = useLogger('Login')
// ...
}
Run Code Online (Sandbox Code Playgroud)
您也可以通过.displayName或获取名称.name。注意.name是指Function.name,这,如果你使用的WebPack,很可能会在生产版本精缩所以你会像“T”或“S”等名称最终如果你需要相同的名称,在组件,您可以分配displayName并让钩子处理它:
const useLogger = (component: React.ComponentType<any>) => {
const name = useLogger(component.displayName || component.name);
return logManager.getLogger(name);
}
const Login: React.FC<Props> = () => {
const log = useLogger(Login)
}
Login.displayName = 'Login';
Run Code Online (Sandbox Code Playgroud)
如果您可以将名称传递给useLogger,但不想displayName每次都设置,您可以使用类似的东西ts-nameof,旨在为您提供像 C# 中的nameof运算符:
const useLogger = (name: string) => {
return logManager.getLogger(name)
}
const Login: React.FC<Props> = () => {
const log = useLogger(nameof(Login))
// ...
}
Run Code Online (Sandbox Code Playgroud)
这里的好处是该名称将在自动重命名后继续存在。这需要一些 bundler 或 Babel 配置。我还没有测试过缩小如何影响这一点,但是ts-nameof您可以使用三种不同的(在撰写本文时):
选择与您的构建管道匹配的第一个。
或者,如果记录器不是特定于组件的,而是特定于模块的,您可以为钩子创建一个工厂,并在您的模块顶部初始化一次:
const makeUseLogger = (name: string) => () => {
return logManager.getLogger(name)
}
// in your module
const useLogger = makeUseLogger('Module name')
const Login: React.FC<Props> = () => {
const log = useLogger()
// ...
}
Run Code Online (Sandbox Code Playgroud)
作为这个的扩展,如果记录器本身实际上不需要成为一个钩子(不使用其他钩子或需要道具等),只需直接在顶层为您的模块制作一个记录器:
const log = logManager.getLogger('Module name')
const Login: React.FC<Props> = () => {
log.info('hello')
}
Run Code Online (Sandbox Code Playgroud)
此外,如果您不介意项目的目录结构泄漏到生产版本中,您可以使用 webpack 技巧:
const useLogger = (component: React.ComponentType<any>) => {
const name = useLogger(component.displayName || component.name);
return logManager.getLogger(name);
}
const Login: React.FC<Props> = () => {
const log = useLogger(Login)
}
Login.displayName = 'Login';
Run Code Online (Sandbox Code Playgroud)
进而
const log = logManager.getLogger(__filename)
Run Code Online (Sandbox Code Playgroud)
在路径为/home/user/project/src/components/Login.ts且 webpack上下文为 的文件中/home/user/project,__filename变量将解析为src/components/Login.ts.
虽然,这可能需要您创建一个 typedef,例如globals.d.ts在其中声明__filenameTypescript的全局变量:
declare global {
__filename: string;
}
Run Code Online (Sandbox Code Playgroud)
注意:这会不会,如果您的构建目标工作umd。
作为旁注,从技术上讲,如果您出于某种原因不想将任何参数传递给useLogging,则可以使用已弃用的 Function.caller属性,例如
function useLogging() {
const caller = (useLogging.caller as React.ComponentType<any>);
const name = caller.displayName || caller.name;
console.log(name);
return logManager.getLogger(name);
}
const Login: React.FC<Props> = () => {
const log = useLogging()
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是,该属性已被弃用,因此您迟早必须对其进行清理,因此请勿在生产代码中这样做。
| 归档时间: |
|
| 查看次数: |
1307 次 |
| 最近记录: |