Il y a quelques autres moyens auxquels je pense que vous pourriez utiliser. La première et la plus simple est celle que Drew a suggérée dans le commentaire, qui consiste à passer simplement le nom du journal comme argument :
const useLogger = (name: string) => {
return logManager.getLogger(name)
}
const Login: React.FC<Props> = () => {
const log = useLogger('Login')
// ...
}
Vous pouvez également obtenir le nom via .displayName
o .name
. Remarquez que .name
se réfère à Function.name
qui, si vous utilisez webpack, seront probablement minifiés dans une version de production, de sorte que vous vous retrouverez avec des noms comme "t" ou "s", etc. Si vous avez besoin du même nom que dans votre composant, vous pouvez assigner displayName
et laisser le crochet s'en occuper :
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';
Si vous êtes d'accord pour passer un nom à useLogger
mais je ne veux pas mettre displayName
à chaque fois, vous pourriez utiliser quelque chose comme ts-nameof
qui vise à vous donner un nameof
opérateur comme en C# :
const useLogger = (name: string) => {
return logManager.getLogger(name)
}
const Login: React.FC<Props> = () => {
const log = useLogger(nameof(Login))
// ...
}
L'avantage est que le nom survivra aux renommages automatiques. Cela nécessite une certaine configuration du bundler ou de Babel. Je n'ai pas testé l'impact de la miniaturisation sur ce point, mais il existe trois versions différentes de ts-nameof
(au moment de la rédaction) que vous pouvez utiliser :
Choisissez le premier qui correspond à votre pipeline de construction.
Alternativement, si le logger n'est pas spécifique aux composants mais spécifique au module vous pourriez créer une fabrique pour le crochet, et l'initialiser une fois au début de votre module :
const makeUseLogger = (name: string) => () => {
return logManager.getLogger(name)
}
// in your module
const useLogger = makeUseLogger('Module name')
const Login: React.FC<Props> = () => {
const log = useLogger()
// ...
}
Dans le prolongement de ceci, si le logger lui-même n'a pas besoin d'être un hook (il n'utilise pas d'autres hooks ou n'a pas besoin de props, etc.), créez simplement un logger pour votre module au niveau supérieur directement :
const log = logManager.getLogger('Module name')
const Login: React.FC<Props> = () => {
log.info('hello')
}
En outre, si la structure des répertoires de votre projet ne vous dérange pas, vous pouvez utiliser une astuce de webpack :
// webpack.config.js
module.exports = {
// ...
node: {
__filename: true
}
}
et ensuite
const log = logManager.getLogger(__filename)
Dans un fichier dont le chemin est /home/user/project/src/components/Login.ts
et l'outil webpack contexte es /home/user/project
le __filename
sera résolue comme étant src/components/Login.ts
.
Cependant, cela nécessitera probablement de créer un typedef, par exemple globals.d.ts
où vous déclarez le __filename
global pour Typescript :
declare global {
__filename: string;
}
Note : ce sera no fonctionne si votre cible de construction est umd
.
En passant, techniquement, si pour une raison quelconque vous ne voulez pas passer d'arguments à useLogging
vous pourrait utiliser le déprécié Function.caller
la propriété, par exemple
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()
// ...
}
Cependant, cette propriété est déprécié donc tu devras nettoyer ça tôt ou tard, donc ne pas faire cela dans le code de production .