Skip to content

Commit 45ed95e

Browse files
authored
Merge branch 'main' into pr/remove-duplicate-samplerate
2 parents 04890d5 + d74dfa0 commit 45ed95e

28 files changed

+1271
-1806
lines changed

.cursor/rules/avoid-use-effect.mdc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
description:
3+
globs: *.tsx,*.jsx
4+
alwaysApply: false
5+
---
6+
### Avoid useEffect
7+
8+
[You Might Not Need `useEffect`](https://react.dev/learn/you-might-not-need-an-effect)
9+
10+
Instead of using `useEffect`, use ref callbacks, event handlers with
11+
`flushSync`, css, `useSyncExternalStore`, etc.
12+
13+
```tsx
14+
// This example was ripped from the docs:
15+
// ✅ Good
16+
function ProductPage({ product, addToCart }) {
17+
function buyProduct() {
18+
addToCart(product)
19+
showNotification(`Added ${product.name} to the shopping cart!`)
20+
}
21+
22+
function handleBuyClick() {
23+
buyProduct()
24+
}
25+
26+
function handleCheckoutClick() {
27+
buyProduct()
28+
navigateTo('/checkout')
29+
}
30+
// ...
31+
}
32+
33+
useEffect(() => {
34+
setCount(count + 1)
35+
}, [count])
36+
37+
// ❌ Avoid
38+
function ProductPage({ product, addToCart }) {
39+
useEffect(() => {
40+
if (product.isInCart) {
41+
showNotification(`Added ${product.name} to the shopping cart!`)
42+
}
43+
}, [product])
44+
45+
function handleBuyClick() {
46+
addToCart(product)
47+
}
48+
49+
function handleCheckoutClick() {
50+
addToCart(product)
51+
navigateTo('/checkout')
52+
}
53+
// ...
54+
}
55+
```
56+
57+
There are a lot more examples in the docs. `useEffect` is not banned or
58+
anything. There are just better ways to handle most cases.
59+
60+
Here's an example of a situation where `useEffect` is appropriate:
61+
62+
```tsx
63+
// ✅ Good
64+
useEffect(() => {
65+
const controller = new AbortController()
66+
67+
window.addEventListener(
68+
'keydown',
69+
(event: KeyboardEvent) => {
70+
if (event.key !== 'Escape') return
71+
72+
// do something based on escape key being pressed
73+
},
74+
{ signal: controller.signal },
75+
)
76+
77+
return () => {
78+
controller.abort()
79+
}
80+
}, [])
81+
```

app/components/error-boundary.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { captureException } from '@sentry/react'
1+
import { captureException } from '@sentry/react-router'
22
import { useEffect, type ReactElement } from 'react'
33
import {
44
type ErrorResponse,

app/entry.server.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { PassThrough } from 'node:stream'
33
import { styleText } from 'node:util'
44
import { contentSecurity } from '@nichtsam/helmet/content'
55
import { createReadableStreamFromReadable } from '@react-router/node'
6-
import * as Sentry from '@sentry/node'
6+
import * as Sentry from '@sentry/react-router'
77
import { isbot } from 'isbot'
88
import { renderToPipeableStream } from 'react-dom/server'
99
import {
@@ -131,11 +131,12 @@ export function handleError(
131131
if (request.signal.aborted) {
132132
return
133133
}
134+
134135
if (error instanceof Error) {
135136
console.error(styleText('red', String(error.stack)))
136-
void Sentry.captureException(error)
137137
} else {
138138
console.error(error)
139-
Sentry.captureException(error)
140139
}
140+
141+
Sentry.captureException(error)
141142
}

app/root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ function App() {
219219
</nav>
220220
</header>
221221

222-
<div className="flex-1 flex flex-col">
222+
<div className="flex flex-1 flex-col">
223223
<Outlet />
224224
</div>
225225

app/routes/_auth+/onboarding.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { CheckboxField, ErrorList, Field } from '#app/components/forms.tsx'
88
import { Spacer } from '#app/components/spacer.tsx'
99
import { StatusButton } from '#app/components/ui/status-button.tsx'
1010
import {
11-
checkCommonPassword,
11+
checkIsCommonPassword,
1212
requireAnonymous,
1313
sessionKey,
1414
signup,
@@ -77,7 +77,7 @@ export async function action({ request }: Route.ActionArgs) {
7777
})
7878
return
7979
}
80-
const isCommonPassword = await checkCommonPassword(data.password)
80+
const isCommonPassword = await checkIsCommonPassword(data.password)
8181
if (isCommonPassword) {
8282
ctx.addIssue({
8383
path: ['password'],

app/routes/_auth+/reset-password.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'
66
import { ErrorList, Field } from '#app/components/forms.tsx'
77
import { StatusButton } from '#app/components/ui/status-button.tsx'
88
import {
9-
checkCommonPassword,
9+
checkIsCommonPassword,
1010
requireAnonymous,
1111
resetUserPassword,
1212
} from '#app/utils/auth.server.ts'
@@ -47,7 +47,7 @@ export async function action({ request }: Route.ActionArgs) {
4747
const formData = await request.formData()
4848
const submission = await parseWithZod(formData, {
4949
schema: ResetPasswordSchema.superRefine(async ({ password }, ctx) => {
50-
const isCommonPassword = await checkCommonPassword(password)
50+
const isCommonPassword = await checkIsCommonPassword(password)
5151
if (isCommonPassword) {
5252
ctx.addIssue({
5353
path: ['password'],

app/routes/settings+/profile.index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const handle: SEOHandle = {
2323
}
2424

2525
const ProfileFormSchema = z.object({
26-
name: NameSchema.optional(),
26+
name: NameSchema.nullable().default(null),
2727
username: UsernameSchema,
2828
})
2929

app/routes/settings+/profile.password.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Button } from '#app/components/ui/button.tsx'
88
import { Icon } from '#app/components/ui/icon.tsx'
99
import { StatusButton } from '#app/components/ui/status-button.tsx'
1010
import {
11-
checkCommonPassword,
11+
checkIsCommonPassword,
1212
getPasswordHash,
1313
requireUserId,
1414
verifyUserPassword,
@@ -74,7 +74,7 @@ export async function action({ request }: Route.ActionArgs) {
7474
message: 'Incorrect password.',
7575
})
7676
}
77-
const isCommonPassword = await checkCommonPassword(newPassword)
77+
const isCommonPassword = await checkIsCommonPassword(newPassword)
7878
if (isCommonPassword) {
7979
ctx.addIssue({
8080
path: ['newPassword'],

app/routes/settings+/profile.password_.create.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Button } from '#app/components/ui/button.tsx'
77
import { Icon } from '#app/components/ui/icon.tsx'
88
import { StatusButton } from '#app/components/ui/status-button.tsx'
99
import {
10-
checkCommonPassword,
10+
checkIsCommonPassword,
1111
getPasswordHash,
1212
requireUserId,
1313
} from '#app/utils/auth.server.ts'
@@ -47,7 +47,7 @@ export async function action({ request }: Route.ActionArgs) {
4747
const submission = await parseWithZod(formData, {
4848
async: true,
4949
schema: CreatePasswordForm.superRefine(async ({ password }, ctx) => {
50-
const isCommonPassword = await checkCommonPassword(password)
50+
const isCommonPassword = await checkIsCommonPassword(password)
5151
if (isCommonPassword) {
5252
ctx.addIssue({
5353
path: ['password'],

app/routes/users+/$username_+/notes.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default function NotesRoute({ loaderData }: Route.ComponentProps) {
3232
const navLinkDefaultClassName =
3333
'line-clamp-2 block rounded-l-full py-2 pl-8 pr-6 text-base lg:text-xl'
3434
return (
35-
<main className="container flex flex-1 min-h-[400px] px-0 pb-12 md:px-8">
35+
<main className="container flex min-h-[400px] flex-1 px-0 pb-12 md:px-8">
3636
<div className="grid w-full grid-cols-4 bg-muted pl-2 md:container md:rounded-3xl md:pr-0">
3737
<div className="relative col-span-1">
3838
<div className="absolute inset-0 flex flex-col">

0 commit comments

Comments
 (0)