fix: sync reactive state with data prop using \$effect

Replaces bare \$state(data.x) initialisers (which only capture the
initial value) with \$state + \$effect pairs so that state stays in sync
whenever page data is invalidated or the URL changes. Affects all list
pages (searchValue) and all edit/detail pages (form fields).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 11:06:30 +01:00
parent dc1850126b
commit b9b98f178f
13 changed files with 60 additions and 0 deletions

View File

@@ -21,6 +21,7 @@
let deleteOpen = $state(false); let deleteOpen = $state(false);
let deleting = $state(false); let deleting = $state(false);
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -28,6 +28,20 @@
); );
let imageId = $state<string | null>(data.article.image ?? null); let imageId = $state<string | null>(data.article.image ?? null);
let authorId = $state(data.article.author?.id ?? ""); let authorId = $state(data.article.author?.id ?? "");
$effect(() => {
title = data.article.title;
slug = data.article.slug;
excerpt = data.article.excerpt ?? "";
content = data.article.content ?? "";
category = data.article.category ?? "";
tags = data.article.tags ?? [];
featured = data.article.featured ?? false;
publishDate = data.article.publish_date
? new Date(data.article.publish_date).toISOString().slice(0, 16)
: "";
imageId = data.article.image ?? null;
authorId = data.article.author?.id ?? "";
});
let selectedAuthor = $derived(data.authors.find((a) => a.id === authorId) ?? null); let selectedAuthor = $derived(data.authors.find((a) => a.id === authorId) ?? null);
let saving = $state(false); let saving = $state(false);
let editorTab = $state<"write" | "preview">("write"); let editorTab = $state<"write" | "preview">("write");

View File

@@ -18,6 +18,7 @@
let deleteOpen = $state(false); let deleteOpen = $state(false);
let deleting = $state(false); let deleting = $state(false);
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -19,6 +19,7 @@
let deleteOpen = $state(false); let deleteOpen = $state(false);
let deleting = $state(false); let deleting = $state(false);
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -16,6 +16,7 @@
const { data } = $props(); const { data } = $props();
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
let deleteTarget: User | null = $state(null); let deleteTarget: User | null = $state(null);
let deleteOpen = $state(false); let deleteOpen = $state(false);

View File

@@ -24,6 +24,15 @@
let photoId = $state<string | null>(data.user.photo ?? null); let photoId = $state<string | null>(data.user.photo ?? null);
let isAdmin = $state(data.user.is_admin ?? false); let isAdmin = $state(data.user.is_admin ?? false);
let saving = $state(false); let saving = $state(false);
$effect(() => {
firstName = data.user.first_name ?? "";
lastName = data.user.last_name ?? "";
artistName = data.user.artist_name ?? "";
avatarId = data.user.avatar ?? null;
bannerId = data.user.banner ?? null;
photoId = data.user.photo ?? null;
isAdmin = data.user.is_admin ?? false;
});
async function handleAvatarUpload(files: File[]) { async function handleAvatarUpload(files: File[]) {
const file = files[0]; const file = files[0];

View File

@@ -18,6 +18,7 @@
let deleteOpen = $state(false); let deleteOpen = $state(false);
let deleting = $state(false); let deleting = $state(false);
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -29,6 +29,20 @@
let selectedModelIds = $state<string[]>( let selectedModelIds = $state<string[]>(
data.video.models?.map((m: { id: string }) => m.id) ?? [], data.video.models?.map((m: { id: string }) => m.id) ?? [],
); );
$effect(() => {
title = data.video.title;
slug = data.video.slug;
description = data.video.description ?? "";
tags = data.video.tags ?? [];
premium = data.video.premium ?? false;
featured = data.video.featured ?? false;
uploadDate = data.video.upload_date
? new Date(data.video.upload_date).toISOString().slice(0, 16)
: "";
imageId = data.video.image ?? null;
movieId = data.video.movie ?? null;
selectedModelIds = data.video.models?.map((m: { id: string }) => m.id) ?? [];
});
let saving = $state(false); let saving = $state(false);
async function handleImageUpload(files: File[]) { async function handleImageUpload(files: File[]) {

View File

@@ -18,6 +18,7 @@
const { data } = $props(); const { data } = $props();
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
const featuredArticle = const featuredArticle =

View File

@@ -39,6 +39,15 @@
let artistName = $state(data.authStatus.user!.artist_name); let artistName = $state(data.authStatus.user!.artist_name);
let description = $state(data.authStatus.user!.description); let description = $state(data.authStatus.user!.description);
let tags = $state(data.authStatus.user!.tags ?? undefined); let tags = $state(data.authStatus.user!.tags ?? undefined);
$effect(() => {
recordings = data.recordings;
firstName = data.authStatus.user!.first_name;
lastName = data.authStatus.user!.last_name;
artistName = data.authStatus.user!.artist_name;
description = data.authStatus.user!.description;
tags = data.authStatus.user!.tags ?? undefined;
email = data.authStatus.user!.email;
});
let email = $state(data.authStatus.user!.email); let email = $state(data.authStatus.user!.email);
let password = $state(""); let password = $state("");

View File

@@ -15,6 +15,7 @@
const { data } = $props(); const { data } = $props();
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => { searchValue = data.search ?? ""; });
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -18,6 +18,9 @@
const { data } = $props(); const { data } = $props();
let searchValue = $state(data.search ?? ""); let searchValue = $state(data.search ?? "");
$effect(() => {
searchValue = data.search ?? "";
});
let searchTimeout: ReturnType<typeof setTimeout>; let searchTimeout: ReturnType<typeof setTimeout>;
function debounceSearch(value: string) { function debounceSearch(value: string) {

View File

@@ -30,6 +30,10 @@
const timeAgo = new TimeAgo("en"); const timeAgo = new TimeAgo("en");
let isLiked = $state(data.likeStatus.liked); let isLiked = $state(data.likeStatus.liked);
let likesCount = $state(data.video.likes_count || 0); let likesCount = $state(data.video.likes_count || 0);
$effect(() => {
isLiked = data.likeStatus.liked;
likesCount = data.video.likes_count || 0;
});
let isLikeLoading = $state(false); let isLikeLoading = $state(false);
let newComment = $state(""); let newComment = $state("");
let showComments = $state(true); let showComments = $state(true);