
var는 계속 중복 선언이 가능한 게 가장 큰 차이점이고, 이 특성이 문제가 생길 수 있기 때문에 es6에서 let과 const가 생겼습니다. let은 중복 선언이 불가능하지만 재할당이 가능한 변수이고, const는 중복 선언 및 재할당 모두 불가능한 상수입니다. 현재는 유지 보수가 용이하여 let과 const만 사용하는 편입니다.
두 개념 모두 특정 함수의 실행 빈도를 조절하는 기술입니다. 먼저 쓰로틀링은 일정 간격마다 함수를 실행하도록 횟수를 제한하는 기술이고, 디바운싱은 연속된 함수의 호출이 들어올 경우 무시하고 있다가 제일 마지막에 호출된 함수만 실행하도록 하는 기술입니다. 지속된 이벤트의 호출에서 중간 호출도 중요하면 쓰로틀링을, 마지막 호출만이 중요하면 디바운싱을 사용하는 게 좋습니다.
호이스팅은 코드 실행 전에 변수 선언과 함수 선언을 스코프의 최상단으로 끌어올리는 것을 뜻합니다. 이를 통해 선언 위치 앞에서도 호출이 가능합니다. 주의할 점은 함수는 어디서든 호출이 가능하지만 var의 경우 선언 전에 호출하면 undefined를 반환하고 const나 let은 오류를 반환합니다.
처음에는 비교적 간단한 토스 API를 사용하려고 했지만, 결제 서비스를 하는 사이트에서 많이 사용하기도 하고 여러 방식으로 결제가 가능한 KG이니시스를 사용하기 위해 포트원 API를 최종적으로 선택하여 사용하게 되었습니다.
마이 페이지의 내가 쓴 공구템에서 입금 여부를 변경할 때, 기존에 테스트할 때는 RLS를 풀어놨기에 그냥 CRUD 기능이 잘 작동했는데, RLS를 다시 설정하고 나서 갑자기 기능이 안 되기 시작했다. 때문에 policy를 다시 확인했고, 역시 update policy가 설정되어 있지 않았다. 때문에 다른 policy에서 설정했던 것처럼 아래와 같이 설정했으나 기능이 여전히 작동하지 않았다.
alter policy "Enable update for users based on user_id"
on "public"."group_applications"
to public
using (
(( SELECT auth.uid() AS uid) = user_id)
);
이유를 생각해보니, 내가 쓴 포스트에 다른 사람들이 신청한 신청서기 때문에, user_id가 내 id와 다를 수밖에 없다. 때문에 일단 로그인 된 모든 사람들이 수정할 수 있도록 변경을 했다.
create policy "Enable insert for authenticated users only"
on "public"."group_applications"
as PERMISSIVE
for UPDATE
to authenticated
using (
true
);
그러나 이렇게 하면 누구나 다 해당 정보를 변경할 수 있기 때문에... 절대로 좋은 방법이 아니라고 생각했다.
때문에 검색을 통해 방법을 알아냈다... 때문에 절대 내 실력이 아니다 ㅠ
alter policy "Enable update for post owners"
on "public"."group_applications"
to authenticated
using (
(auth.uid() IN ( SELECT group_posts.user_id
FROM group_posts
WHERE (group_posts.id = group_applications.post_id)))
);
우선 인증된 사용자만 가능하게 설정한 다음, group_applications 테이블의 post_id와 일치하는 group_posts 테이블의 id를 가진 포스트의 user_id를 선택하고, 현재 사용자의 id가 이 결과에 포함되어 있다면 해당 신청서를 수정할 수 있게 했다.
이를 통해 포스트 작성자만이 신청받은 리스트를 수정할 수 있게 설정했다.
로컬에선 잘 되던 부분이 배포 때 오류를 내서 해결했다.
해당 부분은 결제 파트 쪽이었는데, 서버 사이드인 페이지에 있는 클라이언트 컴포넌트에서 useSearchParams를 사용하려고 하니 나는 오류였고, 이 과정에서 서버 사이드 렌더링과 클라이언트 사이드 렌더링 사이의 불일치가 발생할 수 있어 Next.js가 Suspense 경계로 감싸기를 권장한다고 했다. 해당 클라이언트 컴포넌트의 코드는 다음과 같았다.
// PaymentComplete.tsx
"use client";
import { useSearchParams } from "next/navigation";
function PaymentComplete() {
const searchParams = useSearchParams();
const paymentId = searchParams.get("paymentId");
// 불필요한 코드 생략
}
나는 Suspense 경계로 감싸는 것보다는 좀 더 쉬운 방법을 생각했다. 바로 page 자체에서 searchParams를 받아와서 클라이언트 컴포넌트에 props로 내려주는 방식이었다. 해당 방식을 사용하니 문제 없이 잘 작동했다. 코드는 아래와 같다.
// page.tsx
function PaymentCompletePage({
searchParams,
}: {
searchParams: { paymentId: string };
}) {
return (
<Page>
<PaymentComplete paymentId={searchParams.paymentId as string} />
</Page>
);
}
// PaymentComplete.tsx
function PaymentComplete({ paymentId }: { paymentId: string }) {
// 바로 paymentId를 사용할 수 있다.
}
이런 식으로 page에서 가져온 paymentId를 props로 넘겨주고, 넘겨준 paymentId를 사용하는 방식으로 문제를 해결했다. 우선 현재까지 우리 팀이 진행한 부분은 배포까지 완료되었다.
생각보다 UI 작업이 오래 걸렸고 중간에 supabase 오류도 해결하는 데에 시간을 투자했기에 목표했던 결제 관련 기능을 전부 수행하지 못 했다. UI 작업은 전부 마무리가 되었기 때문에 내일은 결제 기능 구현에 집중할 수 있을 것 같다.