{"id":13494852,"url":"https://github.com/shuding/tilg","last_synced_at":"2025-05-14T15:07:56.615Z","repository":{"id":40574683,"uuid":"437617482","full_name":"shuding/tilg","owner":"shuding","description":"A magical React Hook that helps you debug components.","archived":false,"fork":false,"pushed_at":"2022-12-23T10:28:52.000Z","size":1456,"stargazers_count":2179,"open_issues_count":0,"forks_count":26,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-07T07:47:21.897Z","etag":null,"topics":["debug","logger","react","react-hooks"],"latest_commit_sha":null,"homepage":"https://codesandbox.io/s/usetilg-3kdtz8?file=/src/App.js:274-359","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shuding.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-12T17:56:15.000Z","updated_at":"2025-04-25T00:48:28.000Z","dependencies_parsed_at":"2023-01-30T18:16:31.564Z","dependency_job_id":null,"html_url":"https://github.com/shuding/tilg","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuding%2Ftilg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuding%2Ftilg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuding%2Ftilg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuding%2Ftilg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shuding","download_url":"https://codeload.github.com/shuding/tilg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254169784,"owners_count":22026214,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debug","logger","react","react-hooks"],"created_at":"2024-07-31T19:01:28.816Z","updated_at":"2025-05-14T15:07:56.579Z","avatar_url":"https://github.com/shuding.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# `useTilg`\n\n**Tiny Logger** is a magical React Hook to help you debug your components.\n\nYou can quickly try out the [**demo**](https://codesandbox.io/s/usetilg-3kdtz8?file=/src/App.js:274-359).\n\n\u003cbr/\u003e\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Features](#features)\n  - [Lifecycle Events (What)](#1-lifecycle-events-what)\n  - [Component Name and Props (Who)](#2-component-name-and-props-who)\n  - [Debug Message (Why)](#3-debug-message-why)\n  - [What Has Changed? (Why)](#4-what-has-changed-why)\n  - [Quick Logs (Why)](#5-quick-logs-why)\n- [Advanced Features](#advanced-features)\n  - [Markdown](#markdown)\n  - [Return Original Value](#return-original-value)\n  - [Auto Deduplication](#auto-deduplication)\n  - [CLI Support](#cli-support)\n- [FAQ \u0026 Caveats](#faq--caveats)\n\n\u003cbr/\u003e\n\n## Installation\n\nThe package is released as `tilg`, use:\n\n```sh\nnpm i tilg\n```\n\nto install it with npm. Or you can choose another package manager.\n\n\u003cbr/\u003e\n\n## Features\n\n### 1. Lifecycle Events (What)\n\nSimply insert the `useTilg()` hook into the component, and it will log the **render**, **mount**, **unmount** events in the console:\n\n```jsx\nimport useTilg from 'tilg'\n\nfunction MyButton() {\n  useTilg()\n  return \u003cbutton\u003eClick me\u003c/button\u003e\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"lifecycle event logs\" src=\"/screenshots/life-cycle-events.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eLogs of render and mount events.\u003c/i\u003e\n\u003c/p\u003e\n\n\n### 2. Component Name and Props (Who)\n\nYou might noticed that it also displays the **name** and **props** of the component, which is very helpful for debugging.\n\n```jsx\nimport useTilg from 'tilg'\n\nfunction MyButton({ text }) {\n  useTilg()\n  return \u003cbutton\u003e{text}\u003c/button\u003e\n}\n\nfunction Title({ children }) {\n  useTilg()\n  return \u003ch1\u003e{children}\u003c/h1\u003e\n}\n\nexport default function Page() {\n  return (\n    \u003c\u003e\n      \u003cTitle\u003eWelcome!\u003c/Title\u003e\n      \u003cMyButton text='foo' /\u003e\n      \u003cMyButton text='bar' /\u003e\n    \u003c/\u003e\n  )\n}\n```\n\nWhen there’re multiple elements of the same component being rendered, it adds a counter `\u003cMyButton/\u003e (2)` for distinguishing so you know **who** is logging the information:\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"information logs\" src=\"/screenshots/info.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eInformation of the logged components.\u003c/i\u003e\n\u003c/p\u003e\n\n\n### 3. Debug Message (Why)\n\nAnother critical thing is to know why does a component re-renders. `useTilg` gives you a simple but powerful API for this:\n\n```jsx\nimport { useState } from 'react'\nimport useTilg from 'tilg'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  \n  useTilg()`count = ${count}`\n  \n  return \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n}\n```\n\nWhen appending a [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to the `useTilg()` call, it will also be displayed as the debug message:\n\n```jsx\nuseTilg()`count = ${count}`\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"debug message\" src=\"/screenshots/message.gif\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eLogs of “count = ?”.\u003c/i\u003e\n\u003c/p\u003e\n\nYou can know where the message is from, too:\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"trace\" src=\"/screenshots/trace.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eTrace of the message and a link to the code location.\u003c/i\u003e\n\u003c/p\u003e\n\n### 4. What Has Changed? (Why)\n\nSomething troubles me a lot when debugging a component is, it’s sometimes hard to know which state has changed and triggered a re-render. `useTilg` tracks all the arguments in the debug message and tells you **which one has changed since the previous render**:\n\n```jsx\nimport { useState } from 'react'\nimport useTilg from 'tilg'\n\nfunction MyApp() {\n  const [input, setInput] = useState('')\n  const [count, setCount] = useState(0)\n\n  useTilg()`input = ${input}, count = ${count}`\n\n  return (\n    \u003c\u003e\n      \u003cinput onChange={(e) =\u003e setInput(e.target.value)} value={input} /\u003e\n      \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n    \u003c/\u003e\n  )\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"changed argument\" src=\"/screenshots/changed.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eA hint for the updated part.\u003c/i\u003e\n\u003c/p\u003e\n\n\n### 5. Quick Logs (Why)\n\nIf you don't need a debug message but only want to quickly log some values, just pass them to the hook directly:\n\n```jsx\nimport { useState } from 'react'\nimport useTilg from 'tilg'\n\nfunction MyApp() {\n  const [input, setInput] = useState('')\n  const [count, setCount] = useState(0)\n\n  useTilg(input, count)\n\n  return (\n    \u003c\u003e\n      \u003cinput onChange={(e) =\u003e setInput(e.target.value)} value={input} /\u003e\n      \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n    \u003c/\u003e\n  )\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"value without message\" src=\"/screenshots/bare.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eDebug values quickly.\u003c/i\u003e\n\u003c/p\u003e\n\n\n\u003cbr/\u003e\n\n## Advanced Features\n\n### Markdown\n\nYou can use Markdown's code (`` ` ``), italic (`_` or `*`), and bold (`__` or `**`) syntax in your debug message to make it look nicer:\n\n```jsx\nfunction MyApp() {\n  const [count, setCount] = useState(0)\n\n  useTilg()`**Debug**: \\`count\\` = _${count}_.`\n\n  return \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"markdown syntax\" src=\"/screenshots/markdown.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eMarkdown syntax in log messages.\u003c/i\u003e\n\u003c/p\u003e\n\n\n### Return Original Value\n\nThe `useTilg()` hook also returns its **first argument**, or the **first value** in the template if specified, so you can quickly debug something in-place by wrapping it with `useTilg()`:\n\n```diff\n  function MyApp() {\n    const [count, setCount] = useState(0)\n\n    return \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{\n+     useTilg(count)\n    }\u003c/button\u003e\n  }\n```\n\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"return original value\" src=\"/screenshots/return-value.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eLog and return the original value.\u003c/i\u003e\n\u003c/p\u003e\n\n\n### Auto Deduplication\n\nEven if you have multiple `useTilg()` hooks in the same component, the lifecycle events will only be logged once per component:\n\n```jsx\nfunction MyApp() {\n  const [input, setInput] = useState('')\n  const [count, setCount] = useState(0)\n\n  useTilg()\n  useTilg()`input = ${input}`\n  useTilg()`count = ${count}`\n\n  return (\n    \u003c\u003e\n      \u003cinput onChange={(e) =\u003e setInput(e.target.value)} value={input} /\u003e\n      \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n    \u003c/\u003e\n  )\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"650\" alt=\"deduplication\" src=\"/screenshots/deduplication.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eRender, mount, and unmount events will not be duplicated even if you have multiple useTilg() hooks.\u003c/i\u003e\n\u003c/p\u003e\n\n### CLI Support\n\nIf you are running your component during SSR, or running server-side tests, `useTilg()` properly outputs the result in Node.js CLI too:\n\n```jsx\nfunction App() {\n  const [count, setCount] = useState(42)\n  \n  useTilg()`The answer is ${{ answer: count }}`\n\n  return \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003e{count}\u003c/button\u003e\n}\n```\n\n\u003cp align=center\u003e\n  \u003cimg width=\"962\" alt=\"deduplication\" src=\"/screenshots/cli.png\"\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eNode.js CLI output.\u003c/i\u003e\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\n## FAQ \u0026 Caveats\n\n- **Is it safe to ship code with `useTilg` to production?**  \n  Although `useTilg()` does nothing in a production build (`process.env.NODE_ENV === 'production'`) but only an empty function, I encourge you to remove the hook from the source code after finishing the development of your app.\n\n- **How do you implement this hook? What can I learn from the code?**  \n  It is very hacky. Don't do the same thing especially try it in production, or [you will be fired](https://github.com/facebook/react/blob/0568c0f8cde4ac6657dff9a5a8a7112acc35a748/packages/react/index.js#L35).\n  \n- **Why not design the API as `` useTilg`message` ``?**  \n  Then it will not be identified as a hook, React Refresh and HMR will not work correctly.\n\n\u003cbr/\u003e\n\n## License\n\nThe MIT License (MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuding%2Ftilg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuding%2Ftilg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuding%2Ftilg/lists"}