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
후속 렌더링에서 누락되어 있기 때문에 드롭됩니다.
더 픽스
따라서 예를 수정하려면 오프셋이 아닌 항목을 식별하는 것을 키로 사용해야 합니다.이것은 항목 자체(모든 값을 키로 허용 가능) 또는.id
property(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: @tommy는 eslint-plugin-react 문서에 대한 이 훌륭한 링크를 추천했습니다.이 문서는 위의 설명보다 더 잘 설명됩니다.
언급URL : https://stackoverflow.com/questions/42773892/wrong-components-rendered-by-preact
'programing' 카테고리의 다른 글
특정 JDBC 접속의 데이터베이스 유형을 판별하려면 어떻게 해야 합니까? (0) | 2023.02.22 |
---|---|
Oracle이 없는 경우 삽입 (0) | 2023.02.22 |
WordPress 플러그인의 Array-to-CSV 내보내기 기능에 문제가 있습니다. (0) | 2023.02.22 |
VirtualAlloc() 실패: [0x00000008] 스토리지가 부족하여 이 명령을 처리할 수 없습니다. (0) | 2023.02.22 |
Angular에서의 약속 오브젝트 캐시JS 서비스 (0) | 2023.02.22 |