Я пытаюсь реализовать бесконечную прокрутку, используя useIntersectionObserver. Все работает нормально, пока я не прокрутил и не отправил сообщение, возникла ошибка.
Ошибка
DOMException: не удалось выполнить replaceState в «Истории».
веб.php
Route::get('/dashboard', [DashboardController::class, 'index'])->middleware(['auth', 'verified'])->name('dashboard');
Dashboard.vue
<template>
<Head title = "Dashboard" />
<AuthenticatedLayout>
<div class = "py-2">
<div class = "max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class = "overflow-hidden">
<div class = "py-6 text-gray-900 flex">
<section class = "basis-2/5">
<h3>Profile</h3>
<h3>Logout</h3>
</section>
<section class = "basis-3/5 px-3">
<Form />
<div v-if = "posts.data.length" class = "mt-12" id = "posts">
<Post
v-for = "post in posts.data"
:key = "post.id"
:post = "post"
/>
<div ref = "bottom" class = "-translate-y-32"></div>
</div>
</section>
</div>
</div>
</div>
</div>
</AuthenticatedLayout>
</template>
<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import { Head } from '@inertiajs/vue3';
import Form from '@/Components/Post/Form.vue';
import Post from '@/Components/Post.vue';
import { onMounted, ref } from 'vue';
import { useIntersectionObserver } from '@vueuse/core';
import axios from 'axios';
const props = defineProps({
posts: Object
});
const bottom = ref(null);
const { stop } = useIntersectionObserver(bottom, ([{ isIntersecting }]) => {
if (!isIntersecting) {
return;
}
axios.get(`${props.posts.meta.path}?cursor=${props.posts.meta.next_cursor}`)
.then((response) => {
props.posts.data = [...props.posts.data, ...response.data.data];
props.posts.meta = response.data.meta;
if (!response.data.meta.next_cursor) {
stop();
}
});
});
onMounted(() => {
document.addEventListener('click', function (event) {
if (event.target.matches('.post-body .mention')) {
if (parseInt(event.target.dataset.id) > 0) {
alert(event.target.outerText);
}
}
});
});
</script>
Форма.vue
<template>
<div>
<form @submit.prevent = "post">
<div>
<Tiptap v-model = "form.body" placeholder = "Got something to share?" />
<!-- <TextArea
id = "body"
type = "text"
class = "mt-4 block w-full"
rows = "3"
placeholder = "Got something to share?"
v-model = "form.body"
required
/> -->
<InputError class = "mt-2" :message = "form.errors.body" />
</div>
<div class = "mt-3">
<PrimaryButton :disabled = "form.processing || form.body.length < 1">Post</PrimaryButton>
</div>
</form>
</div>
</template>
<script setup>
import TextArea from '@/Components/TextArea.vue';
import InputError from '@/Components/InputError.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import { useForm } from '@inertiajs/vue3';
import Tiptap from '../Tiptap.vue';
const form = useForm('PostForm', {
body: ''
});
const post = () => {
form.post(route('posts.store'), {
preserveScroll: true,
preserveState: false,
onSuccess: (page) => {
form.reset();
console.info(page.props)
//page.props.posts.data = [[], ...page.props.posts.data];
},
onFinish: (visit) => {
console.info(visit)
}
});
};
</script>
Я решил эту проблему, переназначив props
на ref
, затем используя назначенный ref
вместо реквизита, а затем используя JSON.parse
и JSON.stringify
вот так:
const props = defineProps({
posts: Object
});
const posts = ref(JSON.parse(JSON.stringify(props.posts)));
код аксиомы
axios.get(`${posts.value.meta.path}?cursor=${posts.value.meta.next_cursor}`)
.then((response) => {
posts.value.data = [...posts.value.data, ...response.data.data];
posts.value.meta = response.data.meta;
if (!response.data.meta.next_cursor) {
stop();
}
});
А в Form.vue я установил preserveState
на false
, вот так:
const post = () => form.post(route('posts.store'), {
preserveState: false,
onSuccess: () => form.reset()
});