Svelte 각 작업이 두 번 / 각 바인딩 오류(정의되지 않은 속성을 설정할 수 없음)
나는 요소들을 블록으로 묶고 클릭으로 제거하려고 한다.
<script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, },
];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, elem}, index}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
내 코드에서 나는 두 가지 문제를 가지고 있다:
- 그가 해야 할 것보다 더 많이 만든다
- 바인딩된 요소를 클릭하여 어레이의 항목을 제거한 후 - svelte가 오류를 발생시킵니다
왜 이렇게 되는 거죠?
도움을 청하기 위해서가 아니라, 사람들을 위해, 같은 문제를 해결하기 위해 이 글을 씁니다
이 두 가지 문제는 모두 동일한 원인을 가지고 있기 때문에 여기에 모읍니다:
- 때때로 예상보다 두 배나 더 많은 일을 막는다
- 가끔 블록 던지기 오류
스벨테 컴파일러 버전 3.59.1에서 테스트된 모든 코드
문제 1 - 각 작업이 두 번씩 수행됨
무슨 말이야?
- 각 블록은 모든 반복을 두 번 수행합니다
아래 코드를 보시면 몇 번의 반복이 가능할까요?
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
</script>
{#each foodList as {icon}}
<div> {icon} </div>
{/each}
만약 당신의 대답이 - , 그렇다면 축하해요, 당신이 맞아요.
자, 이제 요소들이 필요해요, 우리는 블록으로 렌더링하고 있어요.
동일한 코드이며, 내부의 각 div 바인딩에 대해 개체에 프로프 '엘렘'을 추가했습니다
아래를 보고 다시 시도해 보십시오. 몇 번의 반복이 가능합니까?
<script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
</script>
{#each foodList as {icon, elem} }
<div
bind:this={elem}
>
{icon}
</div>
{/each}
맞아요... 우리는 더 많은 반복이 있다.
처음에 블록 코드를 추가하면 다음과 같이 볼 수 있습니다:
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elem}
>
{icon}
</div>
{/each}
왜냐하면.
만약 우리가 한다면 -:
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
const elems = [];
</script>
{#each foodList as {icon}, index }
{ console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
>
{icon}
</div>
{/each}
네... 이제 문제가 사라졌고, 우리는... 제가 알아내려고 노력했던 것처럼, 적어도 1년은 오래 사는 벌레입니다. 이는 아웃코드가 복잡해짐에 따라 상황에 따라 다른 문제로 이어진다.
문제 2 - 각 바인딩에서 반복 가능한 배열이 슬라이스된 후 오류가 발생합니다
(예: '정의되지 않은 속성을 설정할 수 없습니다')
무슨 말이야?
- 각 블록 바인딩은 반복 가능한 배열 항목 중 하나를 제거한 후 오류를 발생시킵니다
동일한 예로, 방금 요소에서 어레이 항목 제거를 추가했습니다. 클릭:
<script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elem}
on:click={remove}
>
{icon}
</div>
{/each}
우리는 우리가 그것이 바인딩되었던 - 배열 항목을 클릭하면 그것들이 절단되어 화면에서 손실될 것으로 예상한다. 정답... 하지만 우리는 우리가 기다리던 것처럼 2개가 아니라 블록 메이크 때문에 오류가 났다.
다시 한 번 명확하게 하기 위해, 우리의 코드 단계: foodList 길이는 3 -> 우리는 food 아이콘을 클릭합니다 -> foodList 길이는 2 (클릭된 아이콘으로 항목을 잘라냅니다).
그 후에 음식 목록에서 각각의 왼쪽 아이콘을 렌더링하기 위해 두 번 반복해야 하지만, 그는 세 번을 렌더링했다!
이것이 우리가 새로운 속성을 정의되지 않은 상태로 쓰려고 하는 우리의 코드에 문제가 있는 이유이다. (항목이 잘려서 우리가 그것을 읽으려고 할 때 - 정의되지 않았다.
// foodList [{ icon: '🍲', emle: null, }, { icon: '🥫', emle: null, }] foodList[2].elem = <div>; // "정의되지 않은 속성을 설정할 수 없습니다."
그것은 버그이고 만약 반복적이고 구속력이 있다면 발생한다.
제 질문에 대한 가장 확실한 해결책은 데이터를 여러 어레이로 분리하는 것입니다:
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
let elems = [];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, cmp}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
하지만... 새로운 배열을 추가하여 내부를 살펴봅시다
(반응식으로, 변경할 때마다 배열을 인쇄합니다.)
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
let elems = [];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
$: console.log(elems);
</script>
{#each foodList as {icon, cmp}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
A가 너에게 두 가지 소식이 있는 것 같다
- 우리는 오류가 없다
- 우리는 배열된 새로운 아이템이 있다
이것은 문제가 여전히 존재한다는 것을 의미한다(블록은 슬라이스된 항목에 대해 여전히 1번의 추가 반복을 만든다).
지금은 foodList 슬라이싱 후에 배열을 필터링할 수 있습니다. 페이지 업데이트 후에 다음과 같이 하십시오.
전체 코드:
<script>
import { tick } from 'svelte';
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
let elems = [];
const remove = async (index) => {
foodList.splice(index, 1);
foodList = foodList;
await tick();
elems = elems.filter((elem) => (elem !== null));
};
$: console.log(elems);
</script>
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
: 블록은 여전히 1번 더 작동하고 바인딩된 항목으로 null을 받았습니다. 페이지 업데이트 후에 필터링했습니다.
라스트 스탠드
정말 무슨 말을 해야 할지... 나는 왜 내 코드가 제대로 작동하지 않는지 알아내려고 이 ****에 너무 많은 시간을 낭비했다.
나는 벨벳을 좋아하지만 벌레는 좋아하지 않는다
저는 이 작은 가이드가 여러분 중 몇몇이 많은 시간을 절약하는 데 도움이 되기를 정말 바랍니다.
정정해 주시면 감사하겠습니다. 🐞의 승리를 놓치지 마십시오.
추신.
네, 시간이 걸리긴 하지만... 언제 도움이 필요할지 모르고, 지식을 공유하십시오
'개발하자' 카테고리의 다른 글
테라폼: 변수를 user_data init 스크립트로 전달하려면 어떻게 해야 합니까 (0) | 2023.05.18 |
---|---|
terraformhcl 변수를 맵으로 생성합니다 (0) | 2023.05.17 |
Python: 이메일을 보낼 때 다른 우편함 사용 (0) | 2023.05.16 |
PythonService를 사용합니다.가상 환경을 사용하는 동안 python 서비스를 호스팅하기 위해 exe (1) | 2023.05.16 |
Terraform - 웹 서버에 연결할 수 없음 - 인스턴스가 서비스를 종료했습니다 (0) | 2023.05.15 |