Svelte 구성 요소를 트리거/강제 업데이트하는 방법
3번 반응에 대해 생각해보려고 하는데...
버튼 클릭으로 UI를 강제로 새로 고치고 싶었다. 나는 HTTP 포스트 데이터를 받아들이고, 그것의 슬롯에 대해 객체(http post result)를 반환하는 커스텀 컴포넌트를 사용하고 있다.
나는 비활성화된 기능을 갖고 싶었다. 그래서 "Disable" 버튼을 클릭하면 http api가 호출되고 데이터 뷰가 새로 고쳐집니다.
<script>
export let id
function onDisable() {
fetch('disable-api-url', {id: id})
// Then ??
// What to do after the fetch call, to refresh the view
}
</script>
<AsyncFetcher postParam={id} let:data>
{data.name}
<button on:click={??}>Refresh</button>
<button on:click={onDisable}>Disable Item</button>
</AsyncFetcher>
나는 기분 전환을 위해 그것을 속이려고 노력했지만 소용이 없었다. 만약 끈이 아니라 물체였다면 작동했을 것인데 불행하게도 여기서는 그렇지 않다.
이를 달성하기 위한 올바른 방법은 무엇일까요?
구성요소를 사용하여 페치를 관리하는 것은 매우 파격적이다. 일반적으로 내부 또는 이벤트 핸들러에서 데이터를 가져옵니다:
<script>
import { onMount } from 'svelte';
let initialData;
let otherData;
onMount(async () => {
const res = await fetch('some-url');
initialData = await res.json();
});
async function update() {
const res = await fetch('some-other-url');
otherData = await res.json();
}
</script>
{#if initialData}
<p>the data is {initialData.something}</p>
{/if}
<button on:click={update}>update</button>
완전히 서비스 가능한 답변을 제공하지만, Svelte가 데이터()를 반영하도록 구성 요소를 업데이트하도록 강제하는 솔루션이 있습니다.
; 온라인 예시에서 나온 바닐라, 특별한 변경 사항 없음:
import App from './App.svelte';
var app = new App({
target: document.body
});
export default app;
; 참고:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Svelte app</title>
<script>
window.neek = { nick: true, camp: { bell: "Neek" }, counter: 0 };
</script>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>
; 참고 및 :
<script>
let name = 'world';
$: notneek = window.neek;
function handleClick() {
notneek.counter += 1;
}
window.neek.update = function () {
notneek = notneek;
}
</script>
<h1>Hello { notneek.camp.bell }!</h1>
<button on:click={handleClick}>
Clicked {notneek.counter} {notneek.counter === 1 ? 'time' : 'times'}
</button>
함수가 의 범위 내에 있기 때문에 를 호출하면 재렌더를 강제로 수행할 수 있습니다. 이 설정은 버튼(via)에 의해 사용되는 내부 데이터에 사용되며 딥 속성(예를 들어, )이 컴포넌트 외부에서 업데이트되고 한번 호출되면 반영될 수 있다.
콘솔에 업데이트되지 않은 내용을 입력하고 메모합니다. 이제 콘솔을 입력하면 UI가 로 업데이트됩니다.
무엇보다 동기화하려는 조각만 동기화되도록 기능 내에서 원하는 만큼 세분화할 수 있다.
나의 경우, svelte가 출력을 플러시하지 않았고, 왜냐하면 나는 100% cpu에서 벤치마크를 실행하여 javascript 이벤트 루프를 차단했기 때문이다
이 경우 트릭은 이벤트 루프를 수동으로 차단 해제하는 것입니다
<script>
function sleep(millisec = 0) {
return new Promise((resolve, reject) => {
setTimeout(_ => resolve(), millisec);
});
};
let result = '';
async function runBenchmark() {
for (let step = 0; step < 10; step++) {
// this needs 100% cpu, so no time for svelte render
cpuburn(); result += `${step}: 1.234 sec\n`;
// unblock the JS event loop, so svelte can render
await sleep(10);
}
}
</script>
<pre>{result}</pre>
는 repl(그러나 현재는 repl 런타임에서 버그를 트리거함)
이것을 동기 함수 호출로 해결하는 것은 아마도 불가능할 것이다. (a와 같은 것)
외부 데이터에 의존하지 않는 구성 요소의 재렌더를 강제로 수행하는 다소 까다로운 솔루션은 다음과 같습니다:
<script>
// Await immediately resolved promise to react to value change.
const forceUpdate = async (_) => {};
let doRerender = 0;
</script>
{#await forceUpdate(doRerender) then _}
<ForcedToRerender on:click={() => doRerender++} />
{/await}
좀 더 "원어민적인" 해결책을 찾으려고 했지만, 결국 이것으로 끝이 났습니다. REPL:
(구성요소를 삭제하고 타이머를 사용하여 다시 표시):
<script>
import ForcedToRerender from './ForcedToRerender.svelte'
let visible = true
let rerender = () =>
{
visible=false
setTimeout(()=>{visible = true}, 100)
}
</script>
{#if visible}
<ForcedToRerender />
{/if}
<button on:click={rerender}>Rerender</button>
Forced ToRender.svelte:
<script>
import { onMount } from 'svelte'
let num = 0
let rnd = () => num = Math.random()
onMount(rnd)
</script>
<div on:click={rnd}>
{num}
</div>
이것은 보다시피 효과가 있다.
데이터를 가져오려면 다음을 사용합니다:
<script>
async function fetchData() {
const res = await fetch('/api')
const data = await res.json()
if (res.ok) {
return data
} else {
throw new Error(data)
}
}
</script>
<style>
.error {
color: red;
}
</style>
{#await fetchData}
<p>Fetching...</p>
{:then data}
<div>{JSON.stringify(data)}</div>
{:catch error}
<div class="error">{error.message}</div>
{/await}
데이터를 새로 고치기 위해서는 대기 블록을 다시 실행하므로 관련 상태를 업데이트하여 재렌더를 트리거해야 합니다. 가져오기 기능을 상태 조각에 저장하고 새로 고침 버튼을 클릭하면 다시 할당하여 재렌더를 트리거할 수 있습니다:
<script>
async function fetchData() {
const res = await fetch('/api')
const data = await res.json
if (res.ok) {
return data
} else {
throw new Error(data)
}
}
let promise = fetchData()
</script>
<style>
.error {
color: red;
}
</style>
<button on:click="{() => {promise = fetchdata()}}">Refresh</button>
{#await promise}
<p>Fetching...</p>
{:then data}
<div>{JSON.stringify(data)}</div>
{:catch error}
<div class="error">{error.message}</div>
{/await}
단순히 내부 값만 업데이트하는 것이 아니라 구성 요소를 완전히 다시 로드하기 위한 핵심(말장난이 아닌)은 다음과 같이 사용하는 것입니다:
{#key category_on}
<Testone a={category_on} />
{/key}
변경된 경우 구성 요소가 완전히 다시 로드됩니다
'개발하자' 카테고리의 다른 글
Basic Python calculator (0) | 2023.09.12 |
---|---|
Typescript에 해당하는 typedef (0) | 2023.09.11 |
젠킨스를 사용하여 kubernetes 배포 업데이트 (0) | 2023.09.09 |
swagger 파일을 기반으로 테라폼이 적용된 api 게이트웨이 배포 (0) | 2023.09.09 |
pyinstaller로 생성된 python 실행 파일 자동 업데이트 (0) | 2023.09.08 |