Условный рендеринг в Svelte на основе ответа сервера
Я создаю веб-приложение с Django в качестве сервера и Sveltekit на клиенте.
В процессе регистрации с сервера на указанный пользователем e-mail отправляется ссылка с токеном, при посещении которого пользователь перенаправляется на домен SvelteKit.
Вот в чем проблема: клиент отправляет токен на сервер для проверки, а на сервере у меня есть представление, которое проверяет токен на предмет того, действителен он или просрочен, и отправляет соответствующий ответ клиенту. Теперь, в зависимости от полученного ответа, я хочу условно вывести пользователю нужный блок кода. Если сервер сообщает, что токен действителен, пользователь может завершить регистрацию, в противном случае ему необходимо повторно отправить свой e-mail для получения другого токена.
Проблема, которая у меня возникла, похоже, связана с моим SvelteKit, а не с моим сервером.
Это мой views.py -
@method_decorator(csrf_exempt, name='dispatch')
class ValidateTokenView(View):
def get(self, request, token, *args, **kwargs):
try:
# Check if the token exists in the database
token_instance = EmailConfirmationToken.objects.filter(token=token).first()
print(f"Token received: {token}")
print(f"Token instance retrieved: {token_instance}")
if token_instance:
print(f"Token created at: {token_instance.created_at}")
is_expired = token_instance.is_expired()
print(f"Is token expired? {is_expired}")
if not is_expired:
# If the token is valid and not expired, respond with success
return JsonResponse({'valid': True, 'message': 'Token is valid'})
else:
# If the token is expired, respond with failure
return JsonResponse({'valid': False, 'message': 'Token is expired'}, status=400)
else:
# If the token instance is not found
return JsonResponse({'valid': False, 'message': 'Token is invalid or expired'}, status=400)
except Exception as e:
print(f'Unexpected error: {str(e)}')
return JsonResponse({'error': 'Internal server error'}, status=500)
Итак, на основании операторов печати, которые я написал для отслеживания хода выполнения, валидный токен правильно считается валидным, и Json-ответ на него отправляется клиенту.
В моем SvelteKit есть маршруты > confirm-email > +page.js и +page.svelte
В моем +page.js есть -
export async function load({ url }) {
const token = url.searchParams.get('token');
console.log('Token:', token);
if (!token) {
return { props: { valid: false } };
}
const res = await fetch(`http://localhost:8000/validate-token/${token}`);
console.log('Fetch Response:', res);
if (res.ok) {
const data = await res.json();
console.log('Response Data:', data);
return { props: { valid: data.valid, formData: data.data } };
} else {
return { props: { valid: false } };
}
}
В консоли моего браузера написано -
Fetch Response: Response {type: 'cors', url: 'http://localhost:8000/validate-token/Eg7t0r2GEbTeSIQ3qvk7aiAhhVwYA3Pi/', redirected: true, status: 200, ok: true, …}
+page.js:14 Response Data: {valid: true, message: 'Token is valid'}
Итак, от сервера действительно получен правильный ответ.
Это моя +страница.svelte -
<script>
export let data; // Import the data prop
let { valid, data: formData } = data; // Destructure the data prop
let email = '';
let emailError = '';
let csrfToken = '';
let emailExistsError = '';
let loading = false;
async function handleContinue() {
emailError = validateEmail(email);
if (!emailError) {
loading = true;
try {
csrfToken = await fetchCsrfToken();
const data = await checkEmail(email, csrfToken);
if (data.exists) {
emailExistsError = 'This email address is already registered.';
} else {
emailExistsError = '';
alert(`A new magic link has been sent to ${email}.`);
window.location.href = '/';
}
} catch (error) {
console.error('Error:', error);
} finally {
loading = false;
}
}
}
</script>
<!-- Preceding html -->
{#if valid}
<h1>Almost there!</h1>
<p>Finish creating your account so that you can upgrade to membership.</p>
<div class="input-container">
<label>Your full name</label>
<input type="text" value={formData.fullName} readonly />
</div>
<div class="input-container">
<label>Your email</label>
<input type="email" value={formData.email} readonly />
</div>
<button>Create account</button>
{:else}
<h1 class="expired-header">Your sign up link has expired</h1>
<p class="expired-paragraph">Enter the email address associated with your account, and we’ll send a new magic link to your inbox.</p>
<form on:submit|preventDefault={handleContinue}>
<input
type="email"
name="email"
placeholder="Your email"
bind:value={email}
class:invalid={emailError || emailExistsError}
required
/>
{#if emailError}
<div class="error-message">{emailError}</div>
{/if}
{#if emailExistsError}
<div class="error-message">{emailExistsError}</div>
{/if}
{#if loading}
<div class="loading">Checking email... Please wait.</div>
{/if}
<button type="submit">Continue</button>
</form>
{/if}
</div>
Итак, как видно, я хочу вывести разные блоки кода в зависимости от того, показал ли ответ от сервера действительный токен или нет, но даже когда ответ от сервера говорит, что токен действителен, блок else выше все равно выводится. Блок else отображается всегда.
Я не знаю, где моя реализация идет не так. Данные не импортируются должным образом в мой +page.svelte?
Кроме того, я заметил, что когда страница загружается, проходит несколько секунд, прежде чем в консоли браузера появляется вот это -
Fetch Response: Response {type: 'cors', url: 'http://localhost:8000/validate-token/Eg7t0r2GEbTeSIQ3qvk7aiAhhVwYA3Pi/', redirected: true, status: 200, ok: true, …}
+page.js:14 Response Data: {valid: true, message: 'Token is valid'}
Я думаю, что страница загружается до получения ответа от сервера, и поэтому блок else выводится потому, что Svelte не догадался вовремя вывести блок "# if valid". Правильно ли я рассуждаю?
Кроме того, я заметил еще кое-что: когда я навожу курсор на valid здесь "{#if valid}" в моем Vs-коде, я вижу "let valid: any"
Правильно ли я понимаю, что это происходит потому, что моя программа не имеет достаточно информации для вывода конкретного типа valid
, что указывает на проблему с импортом в +page.svelte?
In your load() function you should not encapsulate the data you return in a {props}
меняю +page.js на -
export async function load({ url }) {
const token = url.searchParams.get('token');
if (!token) {
return { valid: false };
}
const res = await fetch(`http://localhost:8000/validate-token/${token}`);
if (res.ok) {
const data = await res.json();
return { valid: data.valid, formData: data.data };
} else {
return { valid: false };
}
}
А в моем +page.svelte у меня было -
export let data; // Import the data prop
let { valid, formData } = data; // Destructure the data prop