programing

Preact에 의해 잘못된 컴포넌트가 렌더링됨

topblog 2023. 2. 22. 21:29
반응형

Preact에 의해 잘못된 컴포넌트가 렌더링됨

상태 배열에 저장된 항목 목록을 렌더링하기 위해 Preact(모든 목적과 목적, React)를 사용하고 있습니다.각 항목 옆에 제거 버튼이 있습니다.문제는 버튼을 클릭하면 적절한 아이템이 삭제되지만(여러 번 확인했지만), 아이템이 재렌더되어 마지막 아이템이 없어지고 제거된 아이템이 그대로 남아 있다는 것입니다.내 코드(간소화):

import { h, Component } from 'preact';
import Package from './package';

export default class Packages extends Component {
  constructor(props) {
    super(props);
    let packages = [
      'a',
      'b',
      'c',
      'd',
      'e'
    ];
    this.setState({packages: packages});
  }

  render () {
    let packages = this.state.packages.map((tracking, i) => {
      return (
        <div className="package" key={i}>
          <button onClick={this.removePackage.bind(this, tracking)}>X</button>
          <Package tracking={tracking} />
        </div>
      );
    });
    return(
      <div>
        <div className="title">Packages</div>
        <div className="packages">{packages}</div>
      </div>
    );
  }

  removePackage(tracking) {
    this.setState({packages: this.state.packages.filter(e => e !== tracking)});
  }
}

내가 뭘 잘못하고 있지?어떻게든 적극적으로 다시 렌더를 해야 하나요?이게 어떻게 해서든 n+1 케이스인가?

설명:내 문제는 상태 동기성에 있지 않다.위 목록에서 'c'를 제거하도록 선택하면 상태가 올바르게 업데이트됩니다.['a','b','d','e'] 그 은 ,, 시, 시, 표, 음, 음, 음, 음, 음, 음, ,, ,, ,, ,, ,, ,, ,, ,이다.['a','b','c','d']전화할 때마다removePackage 리스트는 되었습니다).console.log내 문제가 아닌 것처럼 보일 수 있도록 진술합니다.

이것은 Precact의 문서에서는 완전히 불충분한 고전적인 문제이기 때문에 개인적으로 사과드립니다!관심 있는 사람이 있으면 언제든지 더 나은 문서를 작성할 수 있도록 도움을 요청하고 있습니다.

여기서 발생하는 것은 어레이 인덱스를 (렌더 내의 맵에서) 키로 사용하고 있다는 것입니다. 가 하는 것에 않습니다.에는 항상 「」, 「VDOM diff」가 .키는 항상0-n서 ''는n는 배열 길이이므로 항목을 삭제하면 목록에서 마지막 키가 삭제됩니다.

설명:키가 렌더링을 초월하다

이 예에서는 (가상) DOM이 초기 렌더에서 어떻게 보일지 상상해 보십시오. '나'라고 하면, 의 항목'라고 3개의 항목 ['a', 'b', 'c']

초기 렌더의 결과는 다음과 같습니다.

<div>
  <div className="title">Packages</div>
  <div className="packages">
    <div className="package" key={0}>
      <button>X</button>
      <Package tracking="a" />
    </div>
    <div className="package" key={1}>
      <button>X</button>
      <Package tracking="b" />
    </div>
    <div className="package" key={2}>
      <button>X</button>
      <Package tracking="c" />
    </div>
  </div>
</div>

두 에서 '가 'X'로 .removePackage()를 설정합니다.state.packages로로 합니다.['a', 'c'] DOM: 、 [ 음 、 DOM ]

<div>
  <div className="title">Packages</div>
  <div className="packages">
    <div className="package" key={0}>
      <button>X</button>
      <Package tracking="a" />
    </div>
    <div className="package" key={1}>
      <button>X</button>
      <Package tracking="c" />
    </div>
  </div>
</div>

는 각만 알고 구조로의 ), VDOM에 알려줍니다.0 ★★★★★★★★★★★★★★★★★」1 자리에 - 우리는 그이 색인에서 를 원했기 을 알고 있습니다.1제거할 수 있습니다.

주의:key는 디폴트 자녀 diff 순서 변경 시멘틱보다 우선됩니다.이 예에서는,key는 항상 0 베이스의 어레이 인덱스, 즉 마지막 항목입니다.key=2후속 렌더링에서 누락되어 있기 때문에 드롭됩니다.

더 픽스

따라서 예를 수정하려면 오프셋이 아닌 항목을 식별하는 것을 키로 사용해야 합니다.이것은 항목 자체(모든 값을 키로 허용 가능) 또는.idproperty(GC를 방해할 수 있는 오브젝트 참조의 산란을 피하기 위해 권장):

let packages = this.state.packages.map((tracking, i) => {
  return (
                                  // ↙️ a better key fixes it :)
    <div className="package" key={tracking}>
      <button onClick={this.removePackage.bind(this, tracking)}>X</button>
      <Package tracking={tracking} />
    </div>
  );
});

휴, 내가 의도했던 것보다 훨씬 더 장황했군.

TL, DR: 어레이 인덱스(반복 인덱스)를 사용하지 않음key기껏해야 디폴트 동작(상하향식 아이 순서 변경)을 흉내내는 것이지만, 더 많은 경우 모든 분산을 마지막 아이로 밀어넣기만 합니다.


edit: @tommyeslint-plugin-react 문서에 대한훌륭한 링크를 추천했습니다.이 문서는 위의 설명보다 더 잘 설명됩니다.

언급URL : https://stackoverflow.com/questions/42773892/wrong-components-rendered-by-preact

반응형