Vyhledávání na webu

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.