본문 바로가기

개발하자

Svelte 각 작업이 두 번 / 각 바인딩 오류(정의되지 않은 속성을 설정할 수 없음)

반응형

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을 받았습니다. 페이지 업데이트 후에 필터링했습니다.

라스트 스탠드

정말 무슨 말을 해야 할지... 나는 왜 내 코드가 제대로 작동하지 않는지 알아내려고 이 ****에 너무 많은 시간을 낭비했다.

나는 벨벳을 좋아하지만 벌레는 좋아하지 않는다

저는 이 작은 가이드가 여러분 중 몇몇이 많은 시간을 절약하는 데 도움이 되기를 정말 바랍니다.

정정해 주시면 감사하겠습니다. 🐞의 승리를 놓치지 마십시오.

추신.

네, 시간이 걸리긴 하지만... 언제 도움이 필요할지 모르고, 지식을 공유하십시오


반응형