React-window: すべてのアイテムがリストの変更に再マウントされます

作成日 2020年02月04日  ·  15コメント  ·  ソース: bvaughn/react-window

これと同じように見える問題があります。 リスト内のアイテムの1つが変更、追加、または削除されるたびに、itemDataが変更されます。 これにより、以前にレンダリングされたすべてのアイテムが(再レンダリングされるだけでなく)再マウントされます。 私のコードは、形式の点では基本的に例と同じです(データとリスト項目は異なりますが、プロジェクトは同じ構造になっています)。

概念的には、memoizeとReact.memoを使用すると、現在マウントされているアイテムの再レンダリングのみが防止されます。 したがって、これらのどちらも、コンポーネントが再マウントされるかどうかに影響を与えるべきではありません。 アイテムを再マウントするかどうかのリストの決定に考慮される他の変数は何ですか? これを、リスト内のすべてのアイテムをレンダリングするために使用されたプロジェクトから変換しています。この場合、アイテムは再マウントされません。 したがって、この場合の唯一の違いは仮想リストです。 私はしばらくこれに固執していて、何かが欠けているように感じます...

最も参考になるコメント

これは、 react-windowchildrenをコンポーネントとして扱うために発生します。これは、コンポーネントを渡すケースが非常に限られているため、render-propsのアンチパターンであると私は信じています。 ほとんどの場合、代わりに矢印関数を使用して、親クロージャからコンポーネントに追加の小道具を渡します。

この問題の修正は非常に簡単です。 React.createElement(children, props)を直接children(props)置き換えるだけです。 残念ながら、これは重大な変更になります。既存のコードの中には、渡された関数がコンポーネントであるという事実に依存し、内部でuseStateようなものを使用するものがあります。

@bvaughnは、v2がnoComponent小道具をすべてのリストに導入し、それをcreateListComponent()渡します:

--- a/src/createListComponent.js
+++ b/src/createListComponent.js
@@ -145,6 +145,7 @@ export default function createListComponent({
   initInstanceProps,
   shouldResetStyleCacheOnItemSizeChange,
   validateProps,
+  noComponent,
 }: {|
   getItemOffset: GetItemOffset,
   getEstimatedTotalSize: GetEstimatedTotalSize,
@@ -321,15 +322,15 @@ export default function createListComponent({
       const items = [];
       if (itemCount > 0) {
         for (let index = startIndex; index <= stopIndex; index++) {
-          items.push(
-            createElement(children, {
-              data: itemData,
-              key: itemKey(index, itemData),
-              index,
-              isScrolling: useIsScrolling ? isScrolling : undefined,
-              style: this._getItemStyle(index),
-            })
-          );
+          const props = {
+            data: itemData,
+            key: itemKey(index, itemData),
+            index,
+            isScrolling: useIsScrolling ? isScrolling : undefined,
+            style: this._getItemStyle(index),
+          }
+
+          items.push(noComponent ? children(props) : createElement(children, props));
         }
       }

全てのコメント15件

私はこの問題がいくらかの愛を得るのを見たいです。 入力のonChangeがFixedSizeListコンポーネントの外部の状態に影響を与えるように、制御されたテキスト入力を含むアイテムを含むFixedSizeListがあります。 テキスト入力キーを押すたびに状態が更新され、リストの再レンダリングがトリガーされます。 普通のことではなく、典型的なReact制御の入力です。 ただし、アンマウント/再マウントのため、テキスト入力はすぐにフォーカスを失います。 ここではスクロールは行われません。 簡単な1項目の例を次に示します。

const ListTest: FC = () => {
  const [value, setValue] = useState('')

  return (
    <FixedSizeList height={150} itemCount={1} itemSize={35} width={300}>
      {({ style }) => (
        <input
          type="text"
          style={style}
          value={value}
          onChange={event => setValue(event.currentTarget.value)}
        />
      )}
    </FixedSizeList>
  )
}

確かに、この場合は再レンダリングのみが行われるべきであり、完全にアンマウントおよび再マウントすることはできません。 何か案は?

あなたが質問しているのは少し異なります、 @ pgostovic 、そして#420の複製のようです。

アイテムレンダラーをインラインで定義しないでください。 親コンポーネントが再レンダリングされるたびに再作成され、フォーカスなどが混乱します。

完全に機能するああ男-私は今ちょっと愚かだと感じています😄。 ありがとう@bvaughn!

心配ない。 よくある間違いです。 上記で定義した方法でこの問題が発生しないように、v2のAPIを変更する予定です(v2を終了した場合)。

@bvaughn私の状況は家主の状況と似ています。 ここでイベント委任を使用して、各リスト要素をクリックしていくつかの効果を生成します。 ただし、スクロールした後、何かを判断するためにReduxからの値を監視する必要があります。 親コンポーネントはリッスンし、それを子コンポーネントに配布するため、再度レンダリングされます。 この問題は、現在のビューポートのリストアイテムが欠落しているが、DOMがまだ存在していることです。 空白の領域をもう一度スクロールすると、リストアイテムが表示されますが、空白の前のスクロールアイテムではありません。 相互作用効果を出すために、変更された値を聞きたいです。 値を聞くと、再レンダリングを再度トリガーする必要があり、リストアイテムが正しくなくなります。 それを解決する方法は?

@ ryanmcclure4あなたはそれに対する解決策を見つけましたか? 私は同じ問題に直面していて、本当にきびきびとした体験を提供することを妨げています。

@bvaughn考え?

@ b52私はしませんでした。 一番下までスクロールすると、ページを追加して追加する非仮想リストを実装することになりました。 仮想リストほど優れたソリューションではありませんが、機能します。

@bvaughnこんにちは、この問題の計画はありますか? 当社の製品は、ノードに変更を加えると、ツリー内のすべてのノードがアンマウントされて再マウントされるという同じ問題に直面しています。 これにより、アクセシビリティの問題が発生し、ノードに真に焦点を合わせることができます。たとえば、ナレーションはselect(focused)ノードを読み取ることができません。

@bvaughnこんにちは、この問題の計画はありますか? 私の製品は、ノードを変更するとツリー内のすべてのノードがアンマウントされて再マウントされるという同じ問題に直面しています。

これは、 react-windowchildrenをコンポーネントとして扱うために発生します。これは、コンポーネントを渡すケースが非常に限られているため、render-propsのアンチパターンであると私は信じています。 ほとんどの場合、代わりに矢印関数を使用して、親クロージャからコンポーネントに追加の小道具を渡します。

この問題の修正は非常に簡単です。 React.createElement(children, props)を直接children(props)置き換えるだけです。 残念ながら、これは重大な変更になります。既存のコードの中には、渡された関数がコンポーネントであるという事実に依存し、内部でuseStateようなものを使用するものがあります。

@bvaughnは、v2がnoComponent小道具をすべてのリストに導入し、それをcreateListComponent()渡します:

--- a/src/createListComponent.js
+++ b/src/createListComponent.js
@@ -145,6 +145,7 @@ export default function createListComponent({
   initInstanceProps,
   shouldResetStyleCacheOnItemSizeChange,
   validateProps,
+  noComponent,
 }: {|
   getItemOffset: GetItemOffset,
   getEstimatedTotalSize: GetEstimatedTotalSize,
@@ -321,15 +322,15 @@ export default function createListComponent({
       const items = [];
       if (itemCount > 0) {
         for (let index = startIndex; index <= stopIndex; index++) {
-          items.push(
-            createElement(children, {
-              data: itemData,
-              key: itemKey(index, itemData),
-              index,
-              isScrolling: useIsScrolling ? isScrolling : undefined,
-              style: this._getItemStyle(index),
-            })
-          );
+          const props = {
+            data: itemData,
+            key: itemKey(index, itemData),
+            index,
+            isScrolling: useIsScrolling ? isScrolling : undefined,
+            style: this._getItemStyle(index),
+          }
+
+          items.push(noComponent ? children(props) : createElement(children, props));
         }
       }

react-virtualizedにもこの問題があるかどうか誰かが知っていますか? OPと同じ問題が発生していますが、これは少しイライラしていましたが、メンテナにとっては問題ではないようです。

編集:react-virtualizedを試してみましたが、残念ながら同じ問題があります。

私は、私の問題を正確に説明するこのスレッドを見つけるまで、なぜすべてが再レンダリングされ続けるのかを理解しようとして、夜中ずっと頭を打っていました。 この問題は、リスト内に画像がある場合に特に顕著になります。 アンマウントマウントは、リストの単一の支柱が変更されるたびにちらつきの問題を引き起こします。

記憶されたリストの例に基づいてこの再マウント動作を示すデモを作成しました。アイテムの1つをクリックすると、コンソールに複数(7回)のmemoログが表示されます。これは、すべてのアイテムが再レンダリングされたことを意味します。 、それは確かにひどいです、私たちがリストにアバターを持っているときはさらに悪いです。

編集:時間があれば再現を提供します

@bvaughnこれはいつ修正できるのだろうか?

@ZYSzysは、ここで何をしようとしているのかFixedSizeListを通常のmapに置き換えたところ、同じ結果が得られましたhttps://codesandbox.io/s/vigorous-archimedes-cvv1c?file=/index.js

あなたの問題はreact-window以内にあるとは思わない

また、メモを試した再レンダリングの問題に直面しています。個別の行コンポーネントのアプローチを作成しても、何も機能しません。

https://user-images.githubusercontent.com/48905195/115861068-c46e5680-a44b-11eb-8c77-985b1da3d2ac.mp4

リストをレンダリングするために渡すオブジェクトの配列があります。 ここで、カートのアイテムを選択してチェックアウトを続行する必要があります。アイテムを選択すると、リスト全体が再レンダリングされますが、これは適切ではありません。

array = [{item:'abc'},{item:'def'},....]; obj={abc:{ isChecked:true },def:{ isChecked:true },...}

つまり、入力のonChangeハンドラーは、アイテムが既に存在する場合はobjに新しいオブジェクトを追加し、その値を変更するだけです。その値を使用して、アイテムがチェックされているかどうかを確認しました。
お気に入り
checked={obj[map.item]?obj[map.item]:false}
ここで、checkedは入力要素の属性です。

@bvaughn
あなたがそれを修正するための解決策を持っているなら、それは私にとって本当に役に立ちます。 ありがとう

このページは役に立ちましたか?
0 / 5 - 0 評価