javascript - React znovu renderuje můj seznam, i když každý prvek v poli má jedinečný klíč
Takže pokud tomu správně rozumím, React znovu vykreslí pouze nové prvky s novými klíči. To u mě ale nefunguje. Mám seznam příspěvků, který je omezen na 3. Když uživatel poscrolluje na konec stránky, zvýším limit o 3, což znamená, že na spodku stránky by měly být zobrazeny 3 starší příspěvky. To, co mám nyní, funguje, ale celý seznam je znovu renderován. A skočí to na začátek, což také nechci (tohle ale dokážu opravit, hlavní problém je znovu renderování). Všechny mají unikátní klíče. Jak mohu tomuto chování zabránit?
thisGetsCalledWhenANewPostComesIn(newPost){
let newPosts = _.clone(this.state.posts);
newPosts.push(newPost);
newPosts.sort((a,b) => b.time_posted - a.time_posted);
this.setState({posts: newPosts});
}
render(){
return (
<div ref={ref => {this.timelineRef = ref;}} style={styles.container}>
{this.state.posts.map(post =>
<Post key={post.id} post={post} />
)}
</div>
);
}
Odpověď č. 1
Používání pouze unikátních klíčů nebrání opětovnému vykreslování komponent, které se nezměnily. Pokud komponenty nezdědíte z PureComponent nebo neimplementujete shouldComponentUpdate, React bude muset komponentu render() a porovnat ji s posledním výsledkem.
Tak proč potřebujeme klíče, když jde vlastně o shouldComponentUpdate?
Účelem přiřazení každé komponentě v seznamu unikátního klíče je předat vlastnosti (props) „správným“ instancím komponent, aby mohly správně porovnat nové a staré vlastnosti.
Představme si, že máme seznam položek, např.:
- A -> instanceKomponentyA
- B -> komponentaInstanceB
- C -> instanceKomponentyC
Po použití filtru musí být seznam znovu vykreslen, aby zobrazil nový seznam komponent, např.:
- C -> ?
Bez správných unikátních klíčů komponenta, která dříve vykreslovala A, nyní obdrží prop(y) pro C. I když C zůstane nezměněno, komponenta bude muset znovu vykreslit, protože obdržela zcela odlišná data:
- C -> componentInstanceA/ACH NE!
S správnými jedinečnými klíči komponenta, která vykreslila C, znovu obdrží C. shouldComponentUpdate pak bude schopna rozpoznat, že výstup render() bude stejný, a komponenta nebude muset být znovu vykreslena:
- C -> instanceKomponentyC
Pokud vykreslení vašeho seznamu položek trvá dlouho, například pokud se jedná o dlouhý seznam nebo každý prvek je složitá sada dat, bude pro vás užitečné zabránit zbytečnému přerekreslování.
Osobní anekdota
V projektu s seznamem stovek položek, z nichž každá vytvářela tisíce DOM elementů, změna z
list.map((item, index) => <SomeComp key={index} ... />)
to
list.map(item => <SomeComp key={item.id} ... />)
snížila dobu vykreslování o několik sekund. Nikdy nepoužívejte index pole jako klíč.
Odpověď č. 2
Budete muset implementovat shouldComponentUpdate(nextProps, nextState) v komponentě Post. Zvažte rozšíření třídy PureComponent pro komponentu Post místo výchozí komponenty React Component.
Hodně štěstí!
PS: Můžete použít řetězec jako ref parametr pro svůj div v metodě render takto:
render() {
return (
<div
ref='myRef'
style={styles.container}
>
{this.getPostViews()}
</div>
);
}
Pak, pokud chcete na tento element odkazovat, použijte ho jako this.refs.myRef. Každopádně, to je jen osobní preference.
