我有一个简洁的代码。我想实现一个子组件更新后父组件重新执行的功能。 我现在遇到一个问题,子组件更新后,父组件函数重新触发,但是会进入死循环
父组件
<script lang="ts">
import { Button } from "$lib/components/ui/button";
import { SquarePlus } from "lucide-svelte";
import Datatable from "$lib/components/datatable/datatable.svelte";
import { getUserListAPI } from "@/apis/hook";
import type { User, UserFilter } from "@/interfaces/user";
import { onMount } from "svelte";
let data: User[] = [];
let dataSize = 0;
let tableFilterDetail:UserFilter = {
pageIndex:1,
pageLimit:10
}
const getData = async (req:UserFilter) => {
//AXIOS post get remote data
const res = await getUserListAPI(req);
data = res.data.rows;
dataSize = res.data.count;
};
onMount(()=>{
getData(tableFilterDetail)
})
$:{
getData(tableFilterDetail)
}
</script>
<div>
<div class="mb-2 w-full flex justify-between items-center">
<h2 class="text-2xl font-bold tracking-tight">User</h2>
<div class="flex items-center">
<Button
variant="success"
class="ml-1 h-10 w-28 flex items-center justify-center rounded-lg "
>
<SquarePlus size="16" />New
</Button>
</div>
</div>
<Datatable {data} {columns} {dataSize} bind:tableFilterDetail/>
</div>
子组件
<script lang="ts">
......
//update state and update tableAttr
$: {
datatableAttr.update((state) => ({
...state,
hiddenColumn: hideForId,
}));
datatableAttr.update((state) => ({
...state,
dataSize: dataSize,
}));
datatableAttr.update((state) => ({
...state,
pageSize: pageSize,
}));
tableFilterDetail = {
pageIndex: $datatableAttr.currentPage,
pageLimit: $datatableAttr.pageSize.value,
};
tableData.set(data);
}
</script>
......
<div class="flex items-center space-x-2">
<label for="itemsPerPage" class="text-gray-700">Page shows:</label>
<Select.Root portal={null} bind:selected={pageSize}>
<Select.Trigger class="w-[130px]">
<Select.Value />
</Select.Trigger>
<Select.Content>
<Select.Group>
{#each tableSize as size}
<Select.Item value={size.value} label={size.label}
>{size.label}</Select.Item
>
{/each}
</Select.Group>
</Select.Content>
<Select.Input name="" />
</Select.Root>
</div>
<div class="flex items-center space-x-2">
<Pagination.Root
count={$datatableAttr.dataSize}
perPage={$datatableAttr.pageSize.value}
let:pages
let:currentPage
bind:page={$datatableAttr.currentPage}
>
<Pagination.Content>
<Pagination.Item>
<Pagination.PrevButton />
</Pagination.Item>
{#each pages as page (page.key)}
{#if page.type === "ellipsis"}
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
{:else}
<Pagination.Item>
<Pagination.Link {page} isActive={currentPage == page.value}>
{page.value}
</Pagination.Link>
</Pagination.Item>
{/if}
{/each}
<Pagination.Item>
<Pagination.NextButton />
</Pagination.Item>
</Pagination.Content>
</Pagination.Root>
</div>
......
可以实现组件第一次加载时请求API,当表数据发生变化时再次请求API并更新表数据,不会进入死循环。
您的孩子中的大型反应式 $: {} 语句将在花括号内的任何内容发生变化时重新运行,数据、存储、过滤器、状态等。因此,一旦它命中,它将处于循环因为过滤器在那里 我建议删除反应语句中对 tableFilterDetail 的任何引用,因为现在当数据更改时,它会更新该过滤器,而当该过滤器更改时,它会更新数据......
// update store and tableData when ONLY the data variable changes
$: data && updateStore()
const updateStore = () => {
datatableAttr.update((state) => ({
...state,
hiddenColumn: hideForId,
dataSize: dataSize,
pageSize: pageSize,
}));
tableData.set(data);
}
// find some other way to update the tableFilterDetail when the filter changes
用于删除过滤器后更新过滤器
perPage={$datatableAttr.pageSize.value}
中的
Pagination
和(当前页面)必须来自 dataTableAttr
商店吗?难道它不能仅仅绑定到传入的tableFilterDetail.pageLimit
吗?如果是这样的话,只需来回推动过滤器,而无需使用商店。
bind:perPage={tableFilterDetail.pageLimit}
bind:currentPage={tableFilterDetail.pageIndex}