{"id":25836006,"url":"https://github.com/bugsplat-git/bugsplat-react","last_synced_at":"2025-03-01T01:38:50.971Z","repository":{"id":42518450,"uuid":"468502877","full_name":"BugSplat-Git/bugsplat-react","owner":"BugSplat-Git","description":"🐛⚛️💥 BugSplat's React error reporter and ErrorBoundary implementation","archived":false,"fork":false,"pushed_at":"2024-11-27T02:23:32.000Z","size":1218,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-27T03:25:51.897Z","etag":null,"topics":["apm","bugsplat","error-reporting","react","reactjs","typescript"],"latest_commit_sha":null,"homepage":"https://docs.bugsplat.com/introduction/getting-started/integrations/web/react","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/BugSplat-Git.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-10T20:37:38.000Z","updated_at":"2024-01-11T09:32:25.000Z","dependencies_parsed_at":"2023-01-18T15:30:19.492Z","dependency_job_id":null,"html_url":"https://github.com/BugSplat-Git/bugsplat-react","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BugSplat-Git%2Fbugsplat-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BugSplat-Git%2Fbugsplat-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BugSplat-Git%2Fbugsplat-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BugSplat-Git%2Fbugsplat-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BugSplat-Git","download_url":"https://codeload.github.com/BugSplat-Git/bugsplat-react/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241304300,"owners_count":19941100,"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":["apm","bugsplat","error-reporting","react","reactjs","typescript"],"created_at":"2025-03-01T01:38:50.280Z","updated_at":"2025-03-01T01:38:50.956Z","avatar_url":"https://github.com/BugSplat-Git.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![bugsplat-github-banner-basic-outline](https://user-images.githubusercontent.com/20464226/149019306-3186103c-5315-4dad-a499-4fd1df408475.png)](https://bugsplat.com)\n\u003cbr/\u003e\n\n# \u003cdiv align=\"center\"\u003eBugSplat\u003c/div\u003e\n\n## **\u003cdiv align=\"center\"\u003eCrash and error reporting built for busy developers.\u003c/div\u003e**\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://twitter.com/BugSplatCo\"\u003e\n        \u003cimg alt=\"Follow @bugsplatco on Twitter\" src=\"https://img.shields.io/twitter/follow/bugsplatco?label=Follow%20BugSplat\u0026style=social\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://discord.gg/K4KjjRV5ve\"\u003e\n        \u003cimg alt=\"Join BugSplat on Discord\" src=\"https://img.shields.io/discord/664965194799251487?label=Join%20Discord\u0026logo=Discord\u0026style=social\"\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\n## Introduction\n\nBugSplat supports the collection of errors in React applications. The\n@bugsplat/react npm package implements an\n[ErrorBoundary](https://reactjs.org/docs/error-boundaries.html)\ncomponent in order to capture rendering errors in child components and\npost them to BugSplat where they can be tracked and managed. Adding BugSplat\nto your React application is extremely easy. Before getting started please\ncomplete the following tasks:\n\n- [Sign up](https://app.bugsplat.com/v2/sign-up) for BugSplat\n- Create a new\n  [database](https://app.bugsplat.com/v2/settings/company/databases)\n  for your application\n- Check out the\n[live demo](https://bugsplat-git.github.io/my-react-crasher/)\nor view a [sample implementation](/examples/my-react-crasher) of BugSplat’s error reporting for React\n\n## Get Started\n\nTo start using BugSplat in your React application, run the following command\nat the root of your project. This will install @bugsplat/react and it's\nsub-dependency, [bugsplat](https://github.com/BugSplat-Git/bugsplat-js).\n\n```shell\nnpm i @bugsplat/react --save\n```\n\nIn addition to standard `package.json` properties `name` and `version`, include\na `database` property to your `package.json` file with the value of your BugSplat\ndatabase. Make sure to replace `{{YOUR_DATABASE_NAME}}` with your actual\ndatabase name.\n\n```jsonc\n// package.json\n{\n  \"name\": \"my-app\",\n  \"version\": \"1.2.0\",\n  \"database\": \"{{YOUR_DATABASE_NAME}}\"\n  // ...\n}\n```\n\nIn the root of your project, import your project's `package.json`. Use it's\n`name`, `database`, and `version` properties to initialize the BugSplat client\nfor sending crashes. This will instantiate a new client instance and store it\ninternally.\n\n```jsx\n// src/index.tsx\n\nimport { createRoot } from 'react-dom/client';\nimport { init } from '@bugsplat/react';\nimport App from './App';\nimport * as packageJson from '../package.json';\n\ninit({\n  database: packageJson.database,\n  name: packageJson.name,\n  version: packageJson.version,\n});\n\nconst root = createRoot(document.getElementById('root'));\n\nroot.render(\u003cApp /\u003e);\n```\n\nYou can now wrap your component trees with `ErrorBoundary` to capture rendering\nerrors and automatically post them to BugSplat with the internal client\ninstance we initialized earlier.\n\n```jsx\n// src/App.tsx\n\nimport { ErrorBoundary } from '@bugsplat/react';\n\nexport default function App() {\n  return (\n    \u003cErrorBoundary fallback={\u003ch1\u003eOops, there was a problem.\u003c/h1\u003e}\u003e\n      \u003cContent\u003e...\u003c/Content\u003e\n    \u003c/ErrorBoundary\u003e\n  );\n}\n```\n\nYou can also access the stored `BugSplat` instance anywhere by\ncalling `getBugSplat()`\n\n```jsx\n// src/App.tsx\n\nimport { getBugSplat } from '@bugsplat/react';\n\nexport default function App() {\n  const handleClick = () =\u003e {\n    getBugSplat().post('There was a problem');\n  };\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eHello, world!\u003c/h1\u003e\n      \u003cbutton onClick={handleClick}\u003ePost Error Report\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Further Integration\n\nWant your error boundary to also handle errors that are not caught by\n`ErrorBoundary`, such as async errors or event handlers? No problem!\n`useErrorHandler` to the rescue. Pass your error to the callback returned from\n`useErrorHandler` in order to propagate the error to the nearest\n`ErrorBoundary`. You can also pass your error directly to `useErrorHandler`\nif you manage the error state yourself or get it from another library.\n\n```jsx\n// src/App.tsx\n\nimport { useState } from 'react'\nimport { ErrorBoundary, useErrorHandler } from '@bugsplat/react';\n\nfunction NestedComponent() {\n  const handleError = useErrorHandler();\n\n  const handleClick = async () =\u003e {\n    try {\n      await doThing();\n    } catch (err) {\n      handleError(err);\n    }\n  };\n\n  return \u003cbutton onClick={handleClick}\u003eDo Thing\u003c/button\u003e;\n}\n\nfunction NestedComponent2() {\n  const [error, setError] = useState\u003cError\u003e()\n\n  useErrorHandler(error)\n\n  const handleClick = async () =\u003e {\n    try {\n      await doThing()\n    } catch (err) {\n      setError(err)\n    }\n  }\n\n  return \u003cbutton onClick={handleClick}\u003eDo Thing\u003c/button\u003e;\n}\n\nexport default function App() {\n  return (\n    \u003cErrorBoundary fallback={\u003ch1\u003eOops, there was a problem.\u003c/h1\u003e}\u003e\n      \u003cNestedComponent /\u003e\n      \u003cNestedComponent2 /\u003e\n    \u003c/ErrorBoundary\u003e\n  );\n}\n```\n\nProviding an instance of BugSplat will allow `ErrorBoundary` to automatically\npost errors it catches to BugSplat.\n\nThe `ErrorBoundary` component is packed with props that can be used to\ncustomize it to fit your needs:\n\n- `fallback`\n- `onMount`\n- `onUnmount`\n- `onError`\n- `beforePost`\n- `onReset`\n- `onResetKeysChange`\n- `disablePost`\n\nWe strongly recommend passing a `fallback` prop that will be rendered\nwhen `ErrorBoundary` encounters an error.\n\nThe `fallback` prop can be any valid element:\n\n```jsx\nfunction Component() {\n  return (\n    \u003cErrorBoundary fallback={\u003cdiv\u003eOops, there was a problem.\u003c/div\u003e}\u003e\n      ...\n    \u003c/ErrorBoundary\u003e\n  );\n}\n```\n\n...or a function that renders one\n\n```jsx\nfunction Component() {\n  return (\n    \u003cErrorBoundary\n      fallback={(fallbackProps) =\u003e \u003cdiv\u003eOops, there was a problem.\u003c/div\u003e}\n    \u003e\n      ...\n    \u003c/ErrorBoundary\u003e\n  );\n}\n```\n\nIf `fallback` is a function, it will be called with\n\n- `error` - the error caught be `ErrorBoundary`\n- `componentStack` - the component stack trace of the error\n- `response` - the BugSplat response of posting error to BugSplat, if applicable\n- `resetErrorBoundary` - a function to call in order to reset the\n  `ErrorBoundary` state\n\nThe fallback will render any time the `ErrorBoundary` catches an error. It is\nuseful to have a fallback UI to gracefully handle errors for your users, while\nstill sending errors to BugSplat behind the scenes.\n\n`ErrorBoundary` accepts a `resetKeys` prop that you can pass with an array of\nvalues that will cause it to automatically reset if one of those values changes.\nThis gives you the power to control the error state from outside of the\ncomponent.\n\n```jsx\nfunction App() {\n  const [error, setError] = useState\u003cError | null\u003e();\n\n  return (\n    \u003cErrorBoundary\n      fallback={(props) =\u003e \u003cFallback {...props} /\u003e}\n      onReset={() =\u003e setError(null)}\n      resetKeys={[error]}\n    \u003e\n      {}\n    \u003c/ErrorBoundary\u003e\n  );\n}\n```\n\n## Advanced Usage\n\n### The `scope` property\n\nIf you know what you're doing and want ErrorBoundary functionality\nbeyond what is possible through props and callbacks, you can extend the\nBugSplat client and pass it to the ErrorBoundary through it's `scope` property.\n\n```jsx\nimport { BugSplat } from 'bugsplat';\nimport { ErrorBoundary } from '@bugsplat/react';\nimport SomeService from '@some/service';\n\nclass CustomBugSplatClient extends BugSplat {\n  async post(error: CustomError) {\n    await SomeService.post(error);\n\n    return super.post(error);\n  }\n}\n\nconst client = new CustomBugSplatClient();\n\nfunction App() {\n  \u003cErrorBoundary scope={{ getClient: () =\u003e client }}\u003e\n    \u003cChildComponents /\u003e\n  \u003c/ErrorBoundary\u003e;\n}\n```\n\n## API\n\n### `init()`\n\n```ts\ninterface BugSplatInit {\n  /**\n   * BugSplat database name that crashes should be posted to\n   */\n  database: string;\n  /**\n   * Name of application\n   */\n  application: string;\n  /**\n   * Version of application.\n   */\n  version: string;\n}\n\n/**\n * Initialize a new BugSplat instance and store the reference in scope\n *\n * @returns function with a callback argument that will be\n * called with the freshly initialized BugSplat instance\n *\n * - Useful to subscribe to events or set default properties\n */\nexport function init({\n  database,\n  application,\n  version,\n}: BugSplatInit): (initializer: (client: BugSplat) =\u003e void) =\u003e void;\n\n/**\n * @example\n */\ninit({\n  database: 'fred',\n  application: 'my-react-crasher',\n  version: '3.2.1',\n})((bugSplat) =\u003e {\n  bugSplat.setDefaultAppKey('Key!');\n  bugSplat.setDefaultUser('User!');\n  bugSplat.setDefaultEmail('fred@bedrock.com');\n  bugSplat.setDefaultDescription('Description!');\n});\n```\n\n### `getBugSplat()`\n\n```ts\n/**\n * Get `BugSplat` instance from application scope\n */\nconst getBugSplat: () =\u003e BugSplat | null;\n```\n\n### `ErrorBoundary`\n\n```typescript\ninterface FallbackProps {\n  /**\n   * Error that caused crash\n   */\n  error: Error;\n  /**\n   * Component stack trace leading to error\n   */\n  componentStack: string | null;\n  /**\n   * Crash post response\n   */\n  response: BugSplatResponse | null;\n  /**\n   * Reset error boundary state.\n   *\n   * This will pass any arguments to the end of onReset when it is called\n   */\n  resetErrorBoundary: (...args: unknown[]) =\u003e void;\n}\n\ntype FallbackElement = ReactElement | null;\n\ntype FallbackRender = (props: FallbackProps) =\u003e FallbackElement;\n\n/**\n * All props in ErrorBoundaryProps are optional,\n * but we recommend at least setting the fallback prop.\n */\ninterface ErrorBoundaryProps {\n  /**\n   * Callback called before error post to BugSplat.\n   *\n   * This will be awaited if it is a promise\n   */\n  beforePost: (\n    bugSplat: BugSplat,\n    error: Error | null,\n    componentStack: string | null\n  ) =\u003e void | Promise\u003cvoid\u003e;\n\n  /**\n   * Callback called when ErrorBoundary catches an error in componentDidCatch()\n   *\n   * This will be awaited if it is a promise\n   */\n  onError: (\n    error: Error,\n    componentStack: string,\n    response: BugSplatResponse | null\n  ) =\u003e void | Promise\u003cvoid\u003e;\n\n  /**\n   * Callback called on componentDidMount().\n   */\n  onMount: () =\u003e void;\n\n  /**\n   * Callback called on componentWillUnmount().\n   */\n  onUnmount: (state: ErrorBoundaryState) =\u003e void;\n\n  /**\n   * Callback called before ErrorBoundary resets internal state,\n   * resulting in rendering children again. This should be\n   * used to ensure that rerendering of children would not\n   * repeat the same error that occurred.\n   *\n   * *This method is not called when ErrorBoundary is reset from a\n   * change in resetKeys - use onResetKeysChange for that.*\n   * @param state - Current error boundary state\n   * @param ...args - Additional arguments passed from where it is called\n   */\n  onReset: (state: ErrorBoundaryState, ...args: unknown[]) =\u003e void;\n\n  /**\n   * Callback called when keys passed to resetKeys are changed.\n   */\n  onResetKeysChange: (prevResetKeys?: unknown[], resetKeys?: unknown[]) =\u003e void;\n\n  /**\n   * Array of values passed from parent scope. When ErrorBoundary\n   * is in an error state, it will check each passed value\n   * and automatically reset if any of the values have changed.\n   */\n  resetKeys?: unknown[];\n\n  /**\n   * Provide a fallback to render when ErrorBoundary catches an error.\n   * Not required, but it is highly recommended to provide a value for this.\n   *\n   * This can be an element or a function that renders an element.\n   */\n  fallback?: FallbackElement | FallbackRender;\n\n  /**\n   * If true, caught errors will not be automatically posted to BugSplat.\n   */\n  disablePost?: boolean;\n\n  /**\n   * Child elements to be rendered when there is no error\n   */\n  children?: ReactNode | ReactNode[];\n\n  /**\n   * __Advanced Use__\n   *\n   * Object used by ErrorBoundary to retrieve a BugSplat client instance.\n   *\n   * Advanced users can extend the `BugSplat` class and use this property\n   * to pass their own scope that will inject the client for use by\n   * ErrorBoundary.\n   */\n  scope: { getClient(): BugSplat | null };\n}\n\ninterface ErrorBoundaryState {\n  error: Error | null;\n  componentStack: string | null;\n  response: BugSplatResponse | null;\n}\n\n/**\n * Handle errors that occur during rendering by wrapping\n * your component tree with ErrorBoundary. Any number of ErrorBoundary\n * components can be rendered in the tree and any rendering error will\n * propagate to the nearest one.\n */\nclass ErrorBoundary extends Component\u003c\n  ErrorBoundaryProps,\n  ErrorBoundaryState\n\u003e\n```\n\n### `withErrorBoundary`\n\n```typescript\n/**\n * Higher order component to wrap your component tree with ErrorBoundary\n */\nfunction withErrorBoundary\u003cP extends Record\u003cstring, unknown\u003e\u003e(\n  Component: ComponentType\u003cP\u003e,\n  errorBoundaryProps: ErrorBoundaryProps = {}\n): ComponentType\u003cP\u003e;\n```\n\n### `useErrorHandler`\n\n```typescript\n/**\n * Utility hook to declaratively or imperatively propagate an\n * error to the nearest error boundary.\n *\n * *Should be called from a child of ErrorBoundary*\n *\n * Propagate error:\n *\n * * Declaratively - by passing an error prop\n * * Imperatively - by calling the returned handler with an error\n *\n * @param errorProp - Will throw when a truthy value is passed\n * @returns Error handler that will throw when called with a truthy value\n */\nfunction useErrorHandler(errorProp?: unknown): (error: unknown) =\u003e void;\n```\n\n## Test Suite\n\nThis package contains both unit and integration tests. To run them,\nuse the package.json scripts provided.\n\n| Tests       | Command                    |\n| ----------- | -------------------------- |\n| Unit        | `npm run test`             |\n| Integration | `npm run test:integration` |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbugsplat-git%2Fbugsplat-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbugsplat-git%2Fbugsplat-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbugsplat-git%2Fbugsplat-react/lists"}