BugSpla
为繁忙的开发者构建了崩溃和错误报告 .
导言
BugSplat支持在React应用程序中收集出错和用户反馈. 这个
@ bugsplat/ react npm 软件包执行一个
边界错误
组件,以获取子组件的渲染错误
把它们送到BugSplat , 在那里可以跟踪和管理它们。 它还规定:
(单位:千美元) useFeedback 用于收集用户反馈的钩子, 如标题, 描述,
文件附件。 在您的 React 应用程序中添加 BugSplate 是极其严重的
很简单。 在开始之前,请完成下列任务:
开始
要在您的 React 应用程序中开始使用 BugSplat, 请运行以下命令 在您的项目根部。 这将安装 @ bugsplat/ react 并且它是 次级依赖性, 错误板。 。 。 .
npm i @bugsplat/react --save
除标准外 package.json 属性 name 财务报告和审定财务报表 version,包括
(单位:千美元) database 属性 package.json 带有您 BugSplat 值的文件
数据库。 确保替换 {{YOUR_DATABASE_NAME}} 与你的实际
数据库名称.
// package.json
{
"name": "my-app",
"version": "1.2.0",
"database": "{{YOUR_DATABASE_NAME}}"
// ...
}
在您的项目根中,导入您的项目 package.json使用它来
name, (中文(简体) ), database,以及 version 要初始化 BugSplate 客户端的属性
因为发送崩溃。 这样可以即时处理一个新的客户端实例并存储它
内部.
// src/index.tsx
import { createRoot } from 'react-dom/client';
import { init } from '@bugsplat/react';
import App from './App';
import * as packageJson from '../package.json';
init({
database: packageJson.database,
name: packageJson.name,
version: packageJson.version,
});
const root = createRoot(document.getElementById('root'));
root.render(<App />);
你现在可以用 ErrorBoundary 要抓取渲染
错误并自动与内部客户端一起发布到 BugSplat
我们刚开始的.
// src/App.tsx
import { ErrorBoundary } from '@bugsplat/react';
export default function App() {
return (
<ErrorBoundary fallback={<h1>Oops, there was a problem.</h1>}>
<Content>...</Content>
</ErrorBoundary>
);
}
您也可以访问存储 BugSplat 地点
电话 getBugSplat()
// src/App.tsx
import { getBugSplat } from '@bugsplat/react';
export default function App() {
const handleClick = () => {
getBugSplat().post('There was a problem');
};
return (
<div>
<h1>Hello, world!</h1>
<button onClick={handleClick}>Post Error Report</button>
</div>
);
}
进一步融合
想要您的错误边界同时处理未被捕获的错误
ErrorBoundary,例如同步错误或事件处理器? 没问题!
useErrorHandler 去营救 将错误传递给返回的调用
useErrorHandler 将错误传播到最近的
ErrorBoundary。也可以将错误直接传递给 useErrorHandler
如果您管理错误, 或从另一个库获取.
// src/App.tsx
import { useState } from 'react'
import { ErrorBoundary, useErrorHandler } from '@bugsplat/react';
function NestedComponent() {
const handleError = useErrorHandler();
const handleClick = async () => {
try {
await doThing();
} catch (err) {
handleError(err);
}
};
return <button onClick={handleClick}>Do Thing</button>;
}
function NestedComponent2() {
const [error, setError] = useState<Error>()
useErrorHandler(error)
const handleClick = async () => {
try {
await doThing()
} catch (err) {
setError(err)
}
}
return <button onClick={handleClick}>Do Thing</button>;
}
export default function App() {
return (
<ErrorBoundary fallback={<h1>Oops, there was a problem.</h1>}>
<NestedComponent />
<NestedComponent2 />
</ErrorBoundary>
);
}
提供 BugSplate 实例将允许 ErrorBoundary 自动
错误被它捕获到 BugSplat .
这个 ErrorBoundary 组件装有可用于
定制以适应您的需要:
fallbackonMountonUnmountonErrorbeforePostonResetonResetKeysChangedisablePost
我们强烈建议通过 fallback 将生成的道具
何时 ErrorBoundary 遇到错误.
这个 fallback 道具可以是任何有效的元素 :
function Component() {
return (
<ErrorBoundary fallback={<div>Oops, there was a problem.</div>}>
...
</ErrorBoundary>
);
}
...或使一个函数
function Component() {
return (
<ErrorBoundary
fallback={(fallbackProps) => <div>Oops, there was a problem.</div>}
>
...
</ErrorBoundary>
);
}
若为 fallback 是函数,将调用
error- 发现的错误是ErrorBoundarycomponentStack- 错误的组件堆栈跟踪response- 向 BugSplat 发布错误的 BugSplate 响应(如果适用)resetErrorBoundary- 调用以重设ErrorBoundary状态
后退会使任何时间 ErrorBoundary 抓取错误。 没错
有用以有一个倒置的 UI 来优雅地处理您的用户的错误,同时
仍然在幕后向 BugSplat 发送错误 .
ErrorBoundary 接受一个 resetKeys 您可以通过一系列
如果其中之一值发生变化,则会使其自动重置的值.
这给了你从外部控制错误状态的权力
组件.
function App() {
const [error, setError] = useState<Error | null>();
return (
<ErrorBoundary
fallback={(props) => <Fallback {...props} />}
onReset={() => setError(null)}
resetKeys={[error]}
>
{}
</ErrorBoundary>
);
}
用户反馈
想要收集用户反馈, 如标题、描述和文件
附件吗? 使用 useFeedback 键入直接向您提交反馈
BugSplate仪表板.
// src/FeedbackForm.tsx
import { useState } from 'react';
import { useFeedback } from '@bugsplat/react';
export default function FeedbackForm() {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [files, setFiles] = useState<FileList | null>(null);
const { postFeedback, loading, response, error } = useFeedback();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const attachments = files
? Array.from(files).map((file) => ({ filename: file.name, data: file }))
: [];
await postFeedback(title, { description, attachments });
};
if (response) {
return <p>Thanks for your feedback!</p>;
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
placeholder="Description"
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
<input
type="file"
multiple
onChange={(e) => setFiles(e.target.files)}
/>
<button type="submit" disabled={loading}>
{loading ? 'Submitting...' : 'Send Feedback'}
</button>
{error && <p>{error.message}</p>}
</form>
);
}
高级使用
这个 scope 属性
如果你知道自己在做什么 想要错误的功能
除了通过道具和召回可能做到的以外,你可以扩展
BugSplate 客户端并通过它传递到错误边界 scope 属性.
import { BugSplat } from 'bugsplat';
import { ErrorBoundary } from '@bugsplat/react';
import SomeService from '@some/service';
class CustomBugSplatClient extends BugSplat {
async post(error: CustomError) {
await SomeService.post(error);
return super.post(error);
}
}
const client = new CustomBugSplatClient();
function App() {
<ErrorBoundary scope={{ getClient: () => client }}>
<ChildComponents />
</ErrorBoundary>;
}
API 密码
init()
interface BugSplatInit {
/**
* BugSplat database name that crashes should be posted to
*/
database: string;
/**
* Name of application
*/
application: string;
/**
* Version of application.
*/
version: string;
}
/**
* Initialize a new BugSplat instance and store the reference in scope
*
* @returns function with a callback argument that will be
* called with the freshly initialized BugSplat instance
*
* - Useful to subscribe to events or set default properties
*/
export function init({
database,
application,
version,
}: BugSplatInit): (initializer: (client: BugSplat) => void) => void;
/**
* @example
*/
init({
database: 'fred',
application: 'my-react-crasher',
version: '3.2.1',
})((bugSplat) => {
bugSplat.setDefaultAppKey('Key!');
bugSplat.setDefaultUser('User!');
bugSplat.setDefaultEmail('[email protected]');
bugSplat.setDefaultDescription('Description!');
});
getBugSplat()
/**
* Get `BugSplat` instance from application scope
*/
const getBugSplat: () => BugSplat | null;
ErrorBoundary
interface FallbackProps {
/**
* Error that caused crash
*/
error: Error;
/**
* Component stack trace leading to error
*/
componentStack: string | null;
/**
* Crash post response
*/
response: BugSplatResponse | null;
/**
* Reset error boundary state.
*
* This will pass any arguments to the end of onReset when it is called
*/
resetErrorBoundary: (...args: unknown[]) => void;
}
type FallbackElement = ReactElement | null;
type FallbackRender = (props: FallbackProps) => FallbackElement;
/**
* All props in ErrorBoundaryProps are optional,
* but we recommend at least setting the fallback prop.
*/
interface ErrorBoundaryProps {
/**
* Callback called before error post to BugSplat.
*
* This will be awaited if it is a promise
*/
beforePost: (
bugSplat: BugSplat,
error: Error | null,
componentStack: string | null
) => void | Promise<void>;
/**
* Callback called when ErrorBoundary catches an error in componentDidCatch()
*
* This will be awaited if it is a promise
*/
onError: (
error: Error,
componentStack: string,
response: BugSplatResponse | null
) => void | Promise<void>;
/**
* Callback called on componentDidMount().
*/
onMount: () => void;
/**
* Callback called on componentWillUnmount().
*/
onUnmount: (state: ErrorBoundaryState) => void;
/**
* Callback called before ErrorBoundary resets internal state,
* resulting in rendering children again. This should be
* used to ensure that rerendering of children would not
* repeat the same error that occurred.
*
* *This method is not called when ErrorBoundary is reset from a
* change in resetKeys - use onResetKeysChange for that.*
* @param state - Current error boundary state
* @param ...args - Additional arguments passed from where it is called
*/
onReset: (state: ErrorBoundaryState, ...args: unknown[]) => void;
/**
* Callback called when keys passed to resetKeys are changed.
*/
onResetKeysChange: (prevResetKeys?: unknown[], resetKeys?: unknown[]) => void;
/**
* Array of values passed from parent scope. When ErrorBoundary
* is in an error state, it will check each passed value
* and automatically reset if any of the values have changed.
*/
resetKeys?: unknown[];
/**
* Provide a fallback to render when ErrorBoundary catches an error.
* Not required, but it is highly recommended to provide a value for this.
*
* This can be an element or a function that renders an element.
*/
fallback?: FallbackElement | FallbackRender;
/**
* If true, caught errors will not be automatically posted to BugSplat.
*/
disablePost?: boolean;
/**
* Child elements to be rendered when there is no error
*/
children?: ReactNode | ReactNode[];
/**
* __Advanced Use__
*
* Object used by ErrorBoundary to retrieve a BugSplat client instance.
*
* Advanced users can extend the `BugSplat` class and use this property
* to pass their own scope that will inject the client for use by
* ErrorBoundary.
*/
scope: { getClient(): BugSplat | null };
}
interface ErrorBoundaryState {
error: Error | null;
componentStack: string | null;
response: BugSplatResponse | null;
}
/**
* Handle errors that occur during rendering by wrapping
* your component tree with ErrorBoundary. Any number of ErrorBoundary
* components can be rendered in the tree and any rendering error will
* propagate to the nearest one.
*/
class ErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
>
withErrorBoundary
/**
* Higher order component to wrap your component tree with ErrorBoundary
*/
function withErrorBoundary<P extends Record<string, unknown>>(
Component: ComponentType<P>,
errorBoundaryProps: ErrorBoundaryProps = {}
): ComponentType<P>;
useErrorHandler
/**
* Utility hook to declaratively or imperatively propagate an
* error to the nearest error boundary.
*
* *Should be called from a child of ErrorBoundary*
*
* Propagate error:
*
* * Declaratively - by passing an error prop
* * Imperatively - by calling the returned handler with an error
*
* @param errorProp - Will throw when a truthy value is passed
* @returns Error handler that will throw when called with a truthy value
*/
function useErrorHandler(errorProp?: unknown): (error: unknown) => void;
useFeedback
/**
* Hook for submitting user feedback to BugSplat.
*
* @returns Object with `postFeedback` function and `loading`/`response`/`error` state
*
* @example
* const { postFeedback, loading, error } = useFeedback();
* await postFeedback('Login button broken', { description: 'Nothing happens when I tap it' });
*/
function useFeedback(): {
/**
* Submit user feedback to BugSplat.
*
* @param title - Feedback title
* @param options - Optional BugSplat options (description, attachments, etc.)
*/
postFeedback: (title: string, options?: BugSplatOptions) => Promise<void>;
/**
* Whether feedback is currently being submitted
*/
loading: boolean;
/**
* BugSplat response from the most recent feedback submission
*/
response: BugSplatResponse | null;
/**
* Error from the most recent feedback submission, if any
*/
error: Error | null;
};
测试套件
这个包包既包括单元测试,也包括集成测试. 为了管理他们, 使用提供的软件包。json脚本.
| 测试 | 命令 |
|---|---|
| 单位 | npm run test |
| 一体化 | npm run test:integration |
