user
라는 props를 받아와서 해당 데이터의 id
와 username
값을 보여준다.// User.js
import React from "react";
function User({ user }) {
return (
<div>
<div>
<b>ID</b> : {user.id}
</div>
<div>
<b>Username : </b> {user.username}
</div>
</div>
);
}
export default User;
// App.js
import "./App.css";
import User from "./User";
function App() {
const user = {
id: 1,
username: "Son",
};
return (
<>
<h1>App</h1>
<User user={user} />
</>
);
}
export default App;
...
<User user={user} />
...
// User.js
...
if (!user) {
return null;
}
return (
...
)
<div>Loading....</div>
과 같은 결과물을 렌더링하면 된다.function Users({ users }) {
// if (!users) return null;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.username}</li>
))}
</ul>
);
}
if (!users) return null;
와 같이 다른 결과물을 반환하는 작업을 해야함 function Users({ users, onToggle }) {
if (!users) return null;
return (
<ul>
{users.map(user => (
<li key={user.id} onClick={() => onToggle(user.id)}>
{user.username}
</li>
))}
</ul>
);
}
Users.defaultProps = {
onToggle: () => {
console.warn('onToggle is missing!');
}
};
defaultProps
설정을 해주는 방법이 있다.// /src/ErrorBoundary.js
import React, { Component } from "react";
class ErrorBoundary extends Component {
state = {
error: false,
};
componentDidCatch(error, info) {
console.log("에러가 발생했습니다.");
console.log({
error,
info,
});
this.setState({
error: true,
});
}
render() {
if (this.state.error) {
return <h1>에러 발생!</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
componentDidCatch
는 두개의 파라미터를 사용하는데 (error, info)ErrorBoundary
컴포넌트로 감싸고// App.js
...
return (
<ErrorBoundary>
<User />
</ErrorBoundary>
);
...
User
컴포넌트에서 null checking 을 하는 코드를 주석을 제거하면// User.js
...
// if (!user) {
// return null;
// }
...
ErrorBoundary
컴포넌트에서 작성한 에러 발생! 문구가 나오게 된다.componentDidCatch
를 사용해서 앱에서 에러가 발생했을 때 사용자에게 에러가 발생했음을 인지시켜줄 수 는 있지만, componentDidCatch
가 실제로 호출되는 일은 서비스에서 "없어야 하는게" 맞다.componentDidCatch
에서 error
와 info
값을 네트워크를 통하여 다른 곳으로 전달해주어야 한다.프론트엔드에서의 오류
프론트엔드에서의 오류는 크게 데이터 영역, 화면 영역 두 가지 영역에서의 오류,
그리고 예상할 수 없는 네트워크 이슈나 특정 브라우저 버전, 단말기 OS 업데이트 같은 외부 요인에 의한 오류나 예상치 못한 런타임 오류로 나눌 수 있다.
데이터 영역, 화면 영역에서 발생하는 오류는 충분히 조심하고 방어할 수 있지만,
외부 요인에 의한 오류나 런타임 오류들은 언제든지 발생할 수 있지만 개발자가 이런 오류를 모두 예측하는것은 거의 불가능에 가깝다.
프런트엔드 모니터링이란
프런트엔드 모니터링은 웹 사이트 또는 앱의 성능을 추적하는 데 사용되는 일련의 프로세스 및 도구.
프런트엔드 모니터링은 주로 사용자가 최종적으로 보는 부분에 중. 여기에는 다음과 같은 문제가 포함됩니다.
- 느린 렌더링
- 일관되지 않거나 응답하지 않는 사용자 경험
- 네트워크 요청/API 오류
- 프레임워크 관련 문제
프런트엔드 모니터링의 중요성
웹 사이트가 더욱 강력해지고 복잡해짐에 따라 성능 유지 관리가 점점 더 어려워지고 있다.
프런트엔드 성능은 사용자 경험의 일부이다다.
때때로 사용자는 웹사이트에서 처음 보고 경험하는 것을 기반으로 그 기업의 품질을 평가한다.
사이트가 중단되거나 오류가 발생한다면 웹사이트의 신뢰와 신뢰성이 상실될 수 있다.
따라서 프런트엔드 모니터링은 견고한 웹 사이트와 앱을 개발하는 데 필수적인 부분이다.
Sentry는 발생한 이벤트 로그에 대하여 다양한 정보를 제공한다.
Context 기능으로 기본적으로 제공되는 정보 외에 특정 이벤트에 대한 추가 정보를 수집할 수도 있다.
Sentry는 Issue Grouping 기능으로 비슷한 이벤트 로그를 하나의 이슈로 통합한다. 이는 비슷한 오류를 파악하고 추적하는 데 큰 도움이 됨.
프론트엔드 뿐만 아니라 .NET, Android, Apple(Cocoa), Go, Java, Kotlin, Python 등의 다양한 플랫폼을 지원
발생한 이슈에 대해 실시간으로 알림을 받을 수 있도록 Slack, Teams, Jira, GitHub 등 다양한 채널을 지원
> npm install --save @sentry/react @sentry/tracing
@Sentry/browser
에서 사용 가능한 모든 메소드는 @Sentry/react
에서 가져올 수 있다.import * as Sentry from '@Sentry/react';
import { BrowserTracing } from '@Sentry/tracing';
Sentry.init({
dsn: 'dsn key', // dsn key 붙여넣으세요.
release: 'release version',
environment: 'production',
normalizeDepth: 6,
integrations: [
new Sentry.Integrations.Breadcrumbs({ console: true }),
new BrowserTracing(),
],
});
Sentry 설정에 필요한 기본 정보
- dsn: 이벤트를 전송하기 위한 식별 키
- release: 애플리케이션 버전 (보통 package.json에 명시한 버전을 사용합니다. 이는 버전별 오류 추적을 용이하게 한다.)
- environment: 애플리케이션 환경 (dev, production 등)
- normalizeDepth: 컨텍스트 데이터를 주어진 깊이로 정규화 (기본값: 3)
- integrations: 플랫폼 SDK별 통합 구성 설정 (React의 경우 react-router integration 설정 가능)
import React from 'react';
import * as Sentry from '@Sentry/react';
<Sentry.ErrorBoundary
fallback={<p>에러가 발생하였습니다. 잠시 후 다시 시도해주세요.</p>}
>
<Example />
</Sentry.ErrorBoundary>;
샘플 비율(SampleRate) 정보
테스트하는 동안, tracesSampleRate를 1.0으로 유지해도 됨. 이것은 브라우저에서 수행된 모든 작업이 Sentry에 트랜잭션으로 전송됨을 의미.
프로덕션에서 Sentry의 트랜잭션 할당량에 도달하지 않고 균일한 샘플 데이터 크기를 수집하려면 이 값을 낮춰야 함.
또는 샘플 데이터를 동적으로 수집하기 위해 traceSampler를 사용하여 이러한 트랜잭션을 필터링할 수 있다.
try {
aFunctionThatMightFail();
} catch (err) {
Sentry.captureException(err);
}
Sentry.captureMessage('에러가 발생하였습니다!');
export default Sentry.withProfiler(App);
//
import React, { Component } from "react";
import * as Sentry from '@sentry/browser';
class ErrorBoundary extends Component {
state = {
error: false,
};
componentDidCatch(error, info) {
console.log("에러가 발생했습니다.");
console.log({
error,
info,
});
this.setState({
error: true,
});
if (process.env.NODE_ENV === 'production') {
Sentry.captureException(error, { extra: info });
}
}
render() {
if (this.state.error) {
return <h1>에러 발생!</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
> npm run build
> npx serve ./build