Ember.js: #each re-render bug

䜜成日 2018幎09月14日  Â·  8コメント  Â·  ゜ヌス: emberjs/ember.js

チェックボックスのリストずしおレンダリングしおいるtrue / false / undefined倀の配列がありたす。
配列芁玠をtrueに、たたはtrueから倉曎するず、チェックボックスのリストが再レンダリングされ、次のindex + 1チェックボックスが倉曎されたチェックボックスずずもに倉曎を継承したす。
コヌド

{{#each range as |value idx|}}
  <label><input type="checkbox" checked={{value}} {{action makeChange idx on="change"}}>{{idx}}: {{value}}</label><br/>
{{/each}}

{{#each range key="@index" as |value idx|}}を䜿甚するず、正しく機胜したす。

ツむドル https 

embereach

Bug Has Reproduction Rendering

最も参考になるコメント

私はここで䜕が起こっおいるのか知っおいるず思いたす。 それは混乱の🍝ですが、私はそれを説明しようずしたす。 倚くの゚ッゞケヌス境界線のナヌザヌ゚ラヌがこれに寄䞎したしたが、バグであるかどうか、これらのいずれかを修正する方法ず方法がよくわかりたせん。

メゞャヌ🔑

たず、 keyパラメヌタヌが{{#each}}䜕をするかを説明する必芁がありたす。 TL; DR DOMを最初から䜜成するのではなく、既存のDOMを再利甚するこずがい぀、どのように意味があるかを刀断しようずしおいたす。

私たちの目的のために、「DOMぞのタッチ」たずえば、テキストノヌドのコンテンツ、属性の曎新、コンテンツの远加たたは削陀などはコストがかかり、可胜な限り回避する必芁があるこずを前提ずしお受け入れたしょう。

かなり単玔なテンプレヌトに焊点を圓おたしょう。

<ul>
  {{#each this.names as |name|}}
    <li>{{name.first}} {{to-upper-case name.last}}</li>
  {{/each}}
</ul>

this.namesが...

[
  { first: "Yehuda", last: "Katz" },
  { first: "Tom", last: "Dale" },
  { first: "Godfrey", last: "Chan" }
]

その埌、あなたは埗るでしょう...

<ul>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
</ul>

ここたでは順調ですね。

リストにアむテムを远加する

では、リストに{ first: "Andrew", last: "Timberlake" }を远加するずどうなるでしょうか。 テンプレヌトが次のDOMを生成するこずを期埅したす。

<ul>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
  <li>Andrew TIMBERLAKE</li>
</ul>

しかし、_どのように_

{{#each}}ヘルパヌを実装する最も単玔な方法は、リストのコンテンツが倉曎されるたびに、リストのすべおのコンテンツをクリアするこずです。 これを行うには、少なくずも23回の操䜜を実行する必芁がありたす。

  • 3぀の<li>ノヌドを削陀したす
  • 4぀の<li>ノヌドを挿入したす
  • 12個のテキストノヌドを挿入したす1぀は名甚、1぀はその間のスペヌス甚、もう1぀は姓甚、4行を掛けたもの
  • to-upper-caseヘルパヌを4回呌び出す

これは...非垞に䞍必芁で高䟡なようです。 最初の3぀の項目は倉曎されおいないこずがわかっおいるので、これらの行の䜜業をスキップできれば䟿利です。

🔑@ index

より良い実装は、既存の行を再利甚し、䞍芁な曎新を行わないこずです。 1぀のアむデアは、行をテンプレヌト内の䜍眮ず単玔に䞀臎させるこずです。 これは基本的にkey="@index"が行うこずです。

  1. 最初のオブゞェクト{ first: "Yehuda", last: "Katz" }を最初の行<li>Yehuda KATZ</li>比范したす。
    1.1。 「むェフダ」===「むェフダ」、䜕もしたせん
    1.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    1.3。 "Katz" === "Katz"、ヘルパヌは "玔粋"であるため、 to-upper-caseヘルパヌを再床呌び出す必芁がないこずがわかっおいたす。したがっお、そのヘルパヌ "KATZ"の出力がわかりたす。 _also_は倉曎されなかったので、ここでは䜕もしたせん
  2. 同様に、行2ず3には䜕の関係もありたせん
  3. DOMには4行目がないため、新しい行を挿入したす
    3.1。 <li>ノヌドを挿入したす
    3.2。 テキストノヌドを挿入したす "Andrew"
    3.3。 テキストノヌドスペヌスを挿入したす
    3.4。 to-upper-caseヘルパヌを呌び出したす "Timberlake"-> "TIMBERLAKE"
    3.5。 テキストノヌドを挿入したす "TIMBERLAKE"

そのため、この実装では、操䜜の総数を23から5に枛らしたした👋比范のコストを手で振っおいたすが、私たちの目的では、他の操䜜ず比范しお比范的安䟡であるず想定しおいたす。 悪くない。

リストの前にアむテムを远加する

しかし、今、リストに{ first: "Andrew", last: "Timberlake" }を远加する代わりに、代わりに远加する堎合はどうなるでしょうか。 テンプレヌトが次のDOMを生成するこずを期埅したす。

<ul>
  <li>Andrew TIMBERLAKE</li>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
</ul>

しかし、_どのように_

  1. 最初のオブゞェクト{ first: "Andrew", last: "Timberlake" }を最初の行<li>Yehuda KATZ</li>比范したす。
    1.1。 "Andrew"== "Yehuda"、テキストノヌドを曎新
    1.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    1.3。 "Timberlake"== "Katz"、 to-upper-caseヘルパヌを再床呌び出したす
    1.4。 テキストノヌドを「KATZ」から「TIMBERLAKE」に曎新したす
  2. 2番目のオブゞェクト{ first: "Yehuda", last: "Katz" }を2番目の行<li>Tom DALE</li> 、別の3぀の操䜜ず比范したす
  3. 2番目のオブゞェクト{ first: "Tom", last: "Dale" }を2番目の行<li>Godfrey CHAN</li> 、別の3぀の操䜜ず比范したす
  4. DOMには4行目がないため、新しい行を挿入したす
    3.1。 <li>ノヌドを挿入したす
    3.2。 テキストノヌドを挿入したす "Godfrey"
    3.3。 テキストノヌドスペヌスを挿入したす
    3.4。 to-upper-caseヘルパヌを呌び出したす「Chan」->「CHAN」
    3.5。 テキストノヌドを挿入したす "CHAN"

これは14回の操䜜です。 痛い

🔑@ identity

抂念的には、远加するか远加するかに関係なく、配列内の1぀のオブゞェクトのみを倉曎挿入しおいるため、これは䞍芁に思えたした。 最適には、远加シナリオで行ったのず同じように、このケヌスを凊理できるはずです。

ここでkey="@identity"が登堎したす。配列内の芁玠の_order_に䟝存する代わりに、JavaScriptオブゞェクトID === を䜿甚したす。

  1. デヌタが最初のオブゞェクト{ first: "Andrew", last: "Timberlake" }䞀臎する === 既存の行を怜玢したす。 䜕も芋぀からなかったので、新しい行を挿入远加したす。
    1.1。 <li>ノヌドを挿入したす
    1.2。 テキストノヌドを挿入したす "Andrew"
    1.3。 テキストノヌドスペヌスを挿入したす
    1.4。 to-upper-caseヘルパヌを呌び出したす "Timberlake"-> "TIMBERLAKE"
    1.5。 テキストノヌドを挿入したす "TIMBERLAKE"
  2. デヌタが2番目のオブゞェクト{ first: "Yehuda", last: "Katz" }䞀臎する === 既存の行を怜玢したす。 <li>Yehuda KATZ</li>芋぀かりたした
    2.1。 「むェフダ」===「むェフダ」、䜕もしたせん
    2.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    2.3。 "Katz" === "Katz"、ヘルパヌは "玔粋"であるため、 to-upper-caseヘルパヌを再床呌び出す必芁がないこずがわかっおいたす。したがっお、そのヘルパヌ "KATZ"の出力がわかりたす。 _also_は倉曎されなかったので、ここでは䜕もしたせん
  3. 同様に、トムずゎッドフリヌの列には䜕の関係もありたせん
  4. 䞀臎しないオブゞェクトを含むすべおの行を削陀したすなし、この堎合は䜕もしたせん

これで、最適な5぀の操䜜に戻りたす。

スケヌルアップする

繰り返したすが、これは👋比范ず簿蚘のコストを手で振っおいたす。 確かに、それらも無料ではなく、この非垞に単玔な䟋では、それらは䟡倀がないかもしれたせん。 しかし、リストが倧きく、各行が耇雑なコンポヌネント倚くのヘルパヌ、蚈算されたプロパティ、サブコンポヌネントなどを呌び出すず想像しおください。 たずえば、LinkedInのニュヌスフィヌドを想像しおみおください。 適切な行ず適切なデヌタを䞀臎させないず、コンポヌネントの匕数が倧量にチャヌンする可胜性があり、予想よりもはるかに倚くのDOM曎新が発生する可胜性がありたす。 間違ったDOM芁玠を䞀臎させたり、カヌ゜ル䜍眮やテキスト遞択状態などのDOM状態を倱ったりするこずにも問題がありたす。

党䜓ずしお、远加の比范ず簿蚘のコストは、実際のアプリではほずんどの堎合簡単に䟡倀がありたす。 key="@identity"はEmberのデフォルトであり、ほずんどすべおの堎合に適切に機胜するため、 {{#each}}を䜿甚する堎合、通垞はkey匕数の蚭定に぀いお心配する必芁はありたせん。

衝突💥

しかし、埅っおください、問題がありたす。 この堎合はどうですか

const YEHUDA = { first: "Yehuda", last: "Katz" };
const TOM = { first: "Tom", last: "Dale" };
const GODFREY = { first: "Godfrey", last: "Chan" };

this.list = [
  YEHUDA,
  TOM,
  GODFREY,
  TOM, // duplicate
  YEHUDA, // duplicate
  YEHUDA, // duplicate
  YEHUDA // duplicate
];

ここでの問題は、同じオブゞェクトが同じリストに耇数回衚瀺される可胜性があるこずです。 これは、単玔な@identityアルゎリズム、特に「デヌタが䞀臎する既存の行を怜玢する === ...」ず蚀った郚分を壊したす。これは、デヌタずDOMの関係が1の堎合にのみ機胜したす。 1、これはこの堎合は圓おはたりたせん。 これは実際にはありそうもないように思われるかもしれたせんが、フレヌムワヌクずしお、私たちはそれを凊理する必芁がありたす。

これを回避するために、䞀皮のハむブリッドアプロヌチを䜿甚しおこれらの衝突を凊理したす。 内郚的には、キヌからDOMぞのマッピングは次のようになりたす。

"YEHUDA" => <li>Yehuda...</li>
"TOM" => <li>Tom...</li>
"GODFREY" => <li>Godfrey...</li>
"TOM-1" => <li>Tom...</li>
"YEHUDA-1" => <li>Yehuda...</li>
"YEHUDA-2" => <li>Yehuda...</li>
"YEHUDA-3" => <li>Yehuda...</li>

ほずんどの堎合、これは非垞にたれであり、発生した堎合、これはほずんどの堎合GoodEnough™で機胜したす。 䜕らかの理由でこれが機胜しない堎合は、い぀でもキヌパスたたはRFC 321のさらに高床なキヌむングメカニズムを䜿甚できたす。

「🐛」に戻る

すべおの話が終わったので、Twiddleのシナリオを芋る準備ができたした。

基本的に、次のリストから始めたした [undefined, undefined, undefined, undefined, undefined] 。

無関係な泚意 Array(5)は[undefined, undefined, undefined, undefined, undefined]ず同じではありたせん。 それはあなたが䞀般的に避けるべきものである「穎あき配列」を生成したす。 ただし、「穎」にアクセスするず実際にundefined返されるため、このバグずは関係ありたせん。 したがっお、私たちの_非垞に狭い_目的のためだけに、それらは同じです。

キヌを指定しなかったため、Emberはデフォルトで@identityを䜿甚したす。 さらに、それらは衝突であるため、次のような結果になりたした。

"undefined" => <input ...> 0: ...,
"undefined-1" => <input ...> 1: ...,
"undefined-2" => <input ...> 2: ...,
"undefined-3" => <input ...> 3: ...,
"undefined-4" => <input ...> 4: ...

ここで、最初のチェックボックスをクリックするずしたす。

  1. これにより、遞択ボックスのデフォルトの動䜜がトリガヌされたす。チェックされた状態がtrueに倉曎されたす。
  2. クリックむベントがトリガヌされ、 {{action}}修食子によっおむンタヌセプトされ、 makeChangeメ゜ッドに再ディスパッチされたす。
  3. リストを[true, undefined, undefined, undefined, undefined]たす。
  4. DOMを曎新したす。

DOMはどのように曎新されたすか

  1. デヌタが最初のオブゞェクトtrue䞀臎する === 既存の行を怜玢したす。 䜕も芋぀からなかったので、新しい行を挿入远加したす<input checked=true ...>0: true...
  2. デヌタが2番目のオブゞェクトundefined䞀臎する === 既存の行を怜玢したす。 <input ...>0: ... 以前は最初の行が芋぀かりたした
    2.1。 {{idx}}テキストノヌドを1曎新したす
    2.2。 それ以倖の堎合、Emberが知る限り、この行では他に䜕も倉曎されおおらず、他に䜕もする必芁はありたせん。
  3. デヌタが3番目のオブゞェクトundefined䞀臎する === 既存の行を怜玢したす。 undefinedを2回目に芋たので、内郚キヌはundefined-1であるため、 <input ...>1: ... 以前は2番目の行が芋぀かりたした。
    3.1。 {{idx}}テキストノヌドを2曎新したす
    3.2。 それ以倖の堎合、Emberが知る限り、この行では他に䜕も倉曎されおおらず、他に䜕もする必芁はありたせん。
  4. 同様に、 undefined-2ずundefined-3曎新したす
  5. 最埌に、䞀臎しないundefined-4行を削陀したす曎新埌に配列内のundefinedが1぀少なくなるため

だから、これはあなたがいじくり回したずきにどのように出力を埗たかを説明しおいたす。 基本的に、すべおのDOM行が1぀䞋にシフトし、新しい行が䞀番䞊に挿入され、残りは{{idx}}が曎新されたす。

本圓に予想倖の郚分は2.2です。 最初のチェックボックスクリックされたチェックボックスが1行䞋がっお2番目の䜍眮に移動したずしおも、Emberのcheckedプロパティがtrueに倉曎されおいるこずを期埅しおいたでしょう。バむンドされた倀は未定矩であるため、Emberがそれをfalseに戻し、チェックを倖すこずを期埅できたす。

しかし、これはそれがどのように機胜するかではありたせん。 冒頭で述べたように、DOMぞのアクセスにはコストがかかりたす。 これには、DOMからの_読み取り_が含たれたす。 曎新のたびに、比范のためにDOMから最新の倀を読み取らなければならない堎合、最適化の目的はほずんど損なわれたす。 したがっお、それを回避するために、DOMに曞き蟌んだ最埌の倀を蚘憶し、DOMから読み戻すこずなく、珟圚の倀をキャッシュされた倀ず比范したした。 違いがある堎合にのみ、新しい倀をDOMに曞き蟌みたすそしお次回のためにキャッシュしたす。 これは、同じ「仮想DOM」アプロヌチを共有するずいう意味ですが、DOM党䜓の「ツリヌ性」を仮想化するのではなく、リヌフノヌドでのみ実行したす。

したがっお、TL; DR、 checkedプロパティたたはテキストフィヌルドのvalueプロパティなどを「バむンド」するず、実際には期埅どおりに機胜したせん。 <div>{{this.name}}</div>をレンダリングし、 jQueryたたはchromeむンスペクタヌを䜿甚しおdiv芁玠のtextContentを手動で曎新した堎合を想像しおみおください。 Emberがそれに気づき、 this.nameを曎新するずは思わなかったでしょう。 これは基本的に同じこずです。 checkedプロパティの曎新はEmberの倖郚で行われたためブラりザのチェックボックスのデフォルトの動䜜を介しお、Emberはそれを認識したせん。

これが{{input}}ヘルパヌが存圚する理由です。 関連するむベントリスナヌを基になるHTML芁玠に登録し、操䜜を適切なプロパティの倉曎に反映しお、関係者レンダリングレむダヌなどに通知できるようにする必芁がありたす。

それが私たちをどこに残すのかわかりたせん。 これが驚くべき理由は理解できたすが、これは䞀連の䞍幞なナヌザヌ゚ラヌであるず蚀いがちです。 おそらく、これらのプロパティを入力芁玠にバむンドするこずに察しおリントする必芁がありたすか

党おのコメント8件

@andrewtimberlakeは、 {{#each range key="@index" as |value idx|}}を䜿甚するこずで問題を回避できるようです。

しかし、バグのように芋えたす。 keyは別の目的のためのものです、 https//www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/ifanchor =各

私はここで䜕が起こっおいるのか知っおいるず思いたす。 それは混乱の🍝ですが、私はそれを説明しようずしたす。 倚くの゚ッゞケヌス境界線のナヌザヌ゚ラヌがこれに寄䞎したしたが、バグであるかどうか、これらのいずれかを修正する方法ず方法がよくわかりたせん。

メゞャヌ🔑

たず、 keyパラメヌタヌが{{#each}}䜕をするかを説明する必芁がありたす。 TL; DR DOMを最初から䜜成するのではなく、既存のDOMを再利甚するこずがい぀、どのように意味があるかを刀断しようずしおいたす。

私たちの目的のために、「DOMぞのタッチ」たずえば、テキストノヌドのコンテンツ、属性の曎新、コンテンツの远加たたは削陀などはコストがかかり、可胜な限り回避する必芁があるこずを前提ずしお受け入れたしょう。

かなり単玔なテンプレヌトに焊点を圓おたしょう。

<ul>
  {{#each this.names as |name|}}
    <li>{{name.first}} {{to-upper-case name.last}}</li>
  {{/each}}
</ul>

this.namesが...

[
  { first: "Yehuda", last: "Katz" },
  { first: "Tom", last: "Dale" },
  { first: "Godfrey", last: "Chan" }
]

その埌、あなたは埗るでしょう...

<ul>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
</ul>

ここたでは順調ですね。

リストにアむテムを远加する

では、リストに{ first: "Andrew", last: "Timberlake" }を远加するずどうなるでしょうか。 テンプレヌトが次のDOMを生成するこずを期埅したす。

<ul>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
  <li>Andrew TIMBERLAKE</li>
</ul>

しかし、_どのように_

{{#each}}ヘルパヌを実装する最も単玔な方法は、リストのコンテンツが倉曎されるたびに、リストのすべおのコンテンツをクリアするこずです。 これを行うには、少なくずも23回の操䜜を実行する必芁がありたす。

  • 3぀の<li>ノヌドを削陀したす
  • 4぀の<li>ノヌドを挿入したす
  • 12個のテキストノヌドを挿入したす1぀は名甚、1぀はその間のスペヌス甚、もう1぀は姓甚、4行を掛けたもの
  • to-upper-caseヘルパヌを4回呌び出す

これは...非垞に䞍必芁で高䟡なようです。 最初の3぀の項目は倉曎されおいないこずがわかっおいるので、これらの行の䜜業をスキップできれば䟿利です。

🔑@ index

より良い実装は、既存の行を再利甚し、䞍芁な曎新を行わないこずです。 1぀のアむデアは、行をテンプレヌト内の䜍眮ず単玔に䞀臎させるこずです。 これは基本的にkey="@index"が行うこずです。

  1. 最初のオブゞェクト{ first: "Yehuda", last: "Katz" }を最初の行<li>Yehuda KATZ</li>比范したす。
    1.1。 「むェフダ」===「むェフダ」、䜕もしたせん
    1.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    1.3。 "Katz" === "Katz"、ヘルパヌは "玔粋"であるため、 to-upper-caseヘルパヌを再床呌び出す必芁がないこずがわかっおいたす。したがっお、そのヘルパヌ "KATZ"の出力がわかりたす。 _also_は倉曎されなかったので、ここでは䜕もしたせん
  2. 同様に、行2ず3には䜕の関係もありたせん
  3. DOMには4行目がないため、新しい行を挿入したす
    3.1。 <li>ノヌドを挿入したす
    3.2。 テキストノヌドを挿入したす "Andrew"
    3.3。 テキストノヌドスペヌスを挿入したす
    3.4。 to-upper-caseヘルパヌを呌び出したす "Timberlake"-> "TIMBERLAKE"
    3.5。 テキストノヌドを挿入したす "TIMBERLAKE"

そのため、この実装では、操䜜の総数を23から5に枛らしたした👋比范のコストを手で振っおいたすが、私たちの目的では、他の操䜜ず比范しお比范的安䟡であるず想定しおいたす。 悪くない。

リストの前にアむテムを远加する

しかし、今、リストに{ first: "Andrew", last: "Timberlake" }を远加する代わりに、代わりに远加する堎合はどうなるでしょうか。 テンプレヌトが次のDOMを生成するこずを期埅したす。

<ul>
  <li>Andrew TIMBERLAKE</li>
  <li>Yehuda KATZ</li>
  <li>Tom DALE</li>
  <li>Godfrey CHAN</li>
</ul>

しかし、_どのように_

  1. 最初のオブゞェクト{ first: "Andrew", last: "Timberlake" }を最初の行<li>Yehuda KATZ</li>比范したす。
    1.1。 "Andrew"== "Yehuda"、テキストノヌドを曎新
    1.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    1.3。 "Timberlake"== "Katz"、 to-upper-caseヘルパヌを再床呌び出したす
    1.4。 テキストノヌドを「KATZ」から「TIMBERLAKE」に曎新したす
  2. 2番目のオブゞェクト{ first: "Yehuda", last: "Katz" }を2番目の行<li>Tom DALE</li> 、別の3぀の操䜜ず比范したす
  3. 2番目のオブゞェクト{ first: "Tom", last: "Dale" }を2番目の行<li>Godfrey CHAN</li> 、別の3぀の操䜜ず比范したす
  4. DOMには4行目がないため、新しい行を挿入したす
    3.1。 <li>ノヌドを挿入したす
    3.2。 テキストノヌドを挿入したす "Godfrey"
    3.3。 テキストノヌドスペヌスを挿入したす
    3.4。 to-upper-caseヘルパヌを呌び出したす「Chan」->「CHAN」
    3.5。 テキストノヌドを挿入したす "CHAN"

これは14回の操䜜です。 痛い

🔑@ identity

抂念的には、远加するか远加するかに関係なく、配列内の1぀のオブゞェクトのみを倉曎挿入しおいるため、これは䞍芁に思えたした。 最適には、远加シナリオで行ったのず同じように、このケヌスを凊理できるはずです。

ここでkey="@identity"が登堎したす。配列内の芁玠の_order_に䟝存する代わりに、JavaScriptオブゞェクトID === を䜿甚したす。

  1. デヌタが最初のオブゞェクト{ first: "Andrew", last: "Timberlake" }䞀臎する === 既存の行を怜玢したす。 䜕も芋぀からなかったので、新しい行を挿入远加したす。
    1.1。 <li>ノヌドを挿入したす
    1.2。 テキストノヌドを挿入したす "Andrew"
    1.3。 テキストノヌドスペヌスを挿入したす
    1.4。 to-upper-caseヘルパヌを呌び出したす "Timberlake"-> "TIMBERLAKE"
    1.5。 テキストノヌドを挿入したす "TIMBERLAKE"
  2. デヌタが2番目のオブゞェクト{ first: "Yehuda", last: "Katz" }䞀臎する === 既存の行を怜玢したす。 <li>Yehuda KATZ</li>芋぀かりたした
    2.1。 「むェフダ」===「むェフダ」、䜕もしたせん
    2.2。 スペヌスには動的デヌタが含たれおいないため、比范は必芁ありたせん
    2.3。 "Katz" === "Katz"、ヘルパヌは "玔粋"であるため、 to-upper-caseヘルパヌを再床呌び出す必芁がないこずがわかっおいたす。したがっお、そのヘルパヌ "KATZ"の出力がわかりたす。 _also_は倉曎されなかったので、ここでは䜕もしたせん
  3. 同様に、トムずゎッドフリヌの列には䜕の関係もありたせん
  4. 䞀臎しないオブゞェクトを含むすべおの行を削陀したすなし、この堎合は䜕もしたせん

これで、最適な5぀の操䜜に戻りたす。

スケヌルアップする

繰り返したすが、これは👋比范ず簿蚘のコストを手で振っおいたす。 確かに、それらも無料ではなく、この非垞に単玔な䟋では、それらは䟡倀がないかもしれたせん。 しかし、リストが倧きく、各行が耇雑なコンポヌネント倚くのヘルパヌ、蚈算されたプロパティ、サブコンポヌネントなどを呌び出すず想像しおください。 たずえば、LinkedInのニュヌスフィヌドを想像しおみおください。 適切な行ず適切なデヌタを䞀臎させないず、コンポヌネントの匕数が倧量にチャヌンする可胜性があり、予想よりもはるかに倚くのDOM曎新が発生する可胜性がありたす。 間違ったDOM芁玠を䞀臎させたり、カヌ゜ル䜍眮やテキスト遞択状態などのDOM状態を倱ったりするこずにも問題がありたす。

党䜓ずしお、远加の比范ず簿蚘のコストは、実際のアプリではほずんどの堎合簡単に䟡倀がありたす。 key="@identity"はEmberのデフォルトであり、ほずんどすべおの堎合に適切に機胜するため、 {{#each}}を䜿甚する堎合、通垞はkey匕数の蚭定に぀いお心配する必芁はありたせん。

衝突💥

しかし、埅っおください、問題がありたす。 この堎合はどうですか

const YEHUDA = { first: "Yehuda", last: "Katz" };
const TOM = { first: "Tom", last: "Dale" };
const GODFREY = { first: "Godfrey", last: "Chan" };

this.list = [
  YEHUDA,
  TOM,
  GODFREY,
  TOM, // duplicate
  YEHUDA, // duplicate
  YEHUDA, // duplicate
  YEHUDA // duplicate
];

ここでの問題は、同じオブゞェクトが同じリストに耇数回衚瀺される可胜性があるこずです。 これは、単玔な@identityアルゎリズム、特に「デヌタが䞀臎する既存の行を怜玢する === ...」ず蚀った郚分を壊したす。これは、デヌタずDOMの関係が1の堎合にのみ機胜したす。 1、これはこの堎合は圓おはたりたせん。 これは実際にはありそうもないように思われるかもしれたせんが、フレヌムワヌクずしお、私たちはそれを凊理する必芁がありたす。

これを回避するために、䞀皮のハむブリッドアプロヌチを䜿甚しおこれらの衝突を凊理したす。 内郚的には、キヌからDOMぞのマッピングは次のようになりたす。

"YEHUDA" => <li>Yehuda...</li>
"TOM" => <li>Tom...</li>
"GODFREY" => <li>Godfrey...</li>
"TOM-1" => <li>Tom...</li>
"YEHUDA-1" => <li>Yehuda...</li>
"YEHUDA-2" => <li>Yehuda...</li>
"YEHUDA-3" => <li>Yehuda...</li>

ほずんどの堎合、これは非垞にたれであり、発生した堎合、これはほずんどの堎合GoodEnough™で機胜したす。 䜕らかの理由でこれが機胜しない堎合は、い぀でもキヌパスたたはRFC 321のさらに高床なキヌむングメカニズムを䜿甚できたす。

「🐛」に戻る

すべおの話が終わったので、Twiddleのシナリオを芋る準備ができたした。

基本的に、次のリストから始めたした [undefined, undefined, undefined, undefined, undefined] 。

無関係な泚意 Array(5)は[undefined, undefined, undefined, undefined, undefined]ず同じではありたせん。 それはあなたが䞀般的に避けるべきものである「穎あき配列」を生成したす。 ただし、「穎」にアクセスするず実際にundefined返されるため、このバグずは関係ありたせん。 したがっお、私たちの_非垞に狭い_目的のためだけに、それらは同じです。

キヌを指定しなかったため、Emberはデフォルトで@identityを䜿甚したす。 さらに、それらは衝突であるため、次のような結果になりたした。

"undefined" => <input ...> 0: ...,
"undefined-1" => <input ...> 1: ...,
"undefined-2" => <input ...> 2: ...,
"undefined-3" => <input ...> 3: ...,
"undefined-4" => <input ...> 4: ...

ここで、最初のチェックボックスをクリックするずしたす。

  1. これにより、遞択ボックスのデフォルトの動䜜がトリガヌされたす。チェックされた状態がtrueに倉曎されたす。
  2. クリックむベントがトリガヌされ、 {{action}}修食子によっおむンタヌセプトされ、 makeChangeメ゜ッドに再ディスパッチされたす。
  3. リストを[true, undefined, undefined, undefined, undefined]たす。
  4. DOMを曎新したす。

DOMはどのように曎新されたすか

  1. デヌタが最初のオブゞェクトtrue䞀臎する === 既存の行を怜玢したす。 䜕も芋぀からなかったので、新しい行を挿入远加したす<input checked=true ...>0: true...
  2. デヌタが2番目のオブゞェクトundefined䞀臎する === 既存の行を怜玢したす。 <input ...>0: ... 以前は最初の行が芋぀かりたした
    2.1。 {{idx}}テキストノヌドを1曎新したす
    2.2。 それ以倖の堎合、Emberが知る限り、この行では他に䜕も倉曎されおおらず、他に䜕もする必芁はありたせん。
  3. デヌタが3番目のオブゞェクトundefined䞀臎する === 既存の行を怜玢したす。 undefinedを2回目に芋たので、内郚キヌはundefined-1であるため、 <input ...>1: ... 以前は2番目の行が芋぀かりたした。
    3.1。 {{idx}}テキストノヌドを2曎新したす
    3.2。 それ以倖の堎合、Emberが知る限り、この行では他に䜕も倉曎されおおらず、他に䜕もする必芁はありたせん。
  4. 同様に、 undefined-2ずundefined-3曎新したす
  5. 最埌に、䞀臎しないundefined-4行を削陀したす曎新埌に配列内のundefinedが1぀少なくなるため

だから、これはあなたがいじくり回したずきにどのように出力を埗たかを説明しおいたす。 基本的に、すべおのDOM行が1぀䞋にシフトし、新しい行が䞀番䞊に挿入され、残りは{{idx}}が曎新されたす。

本圓に予想倖の郚分は2.2です。 最初のチェックボックスクリックされたチェックボックスが1行䞋がっお2番目の䜍眮に移動したずしおも、Emberのcheckedプロパティがtrueに倉曎されおいるこずを期埅しおいたでしょう。バむンドされた倀は未定矩であるため、Emberがそれをfalseに戻し、チェックを倖すこずを期埅できたす。

しかし、これはそれがどのように機胜するかではありたせん。 冒頭で述べたように、DOMぞのアクセスにはコストがかかりたす。 これには、DOMからの_読み取り_が含たれたす。 曎新のたびに、比范のためにDOMから最新の倀を読み取らなければならない堎合、最適化の目的はほずんど損なわれたす。 したがっお、それを回避するために、DOMに曞き蟌んだ最埌の倀を蚘憶し、DOMから読み戻すこずなく、珟圚の倀をキャッシュされた倀ず比范したした。 違いがある堎合にのみ、新しい倀をDOMに曞き蟌みたすそしお次回のためにキャッシュしたす。 これは、同じ「仮想DOM」アプロヌチを共有するずいう意味ですが、DOM党䜓の「ツリヌ性」を仮想化するのではなく、リヌフノヌドでのみ実行したす。

したがっお、TL; DR、 checkedプロパティたたはテキストフィヌルドのvalueプロパティなどを「バむンド」するず、実際には期埅どおりに機胜したせん。 <div>{{this.name}}</div>をレンダリングし、 jQueryたたはchromeむンスペクタヌを䜿甚しおdiv芁玠のtextContentを手動で曎新した堎合を想像しおみおください。 Emberがそれに気づき、 this.nameを曎新するずは思わなかったでしょう。 これは基本的に同じこずです。 checkedプロパティの曎新はEmberの倖郚で行われたためブラりザのチェックボックスのデフォルトの動䜜を介しお、Emberはそれを認識したせん。

これが{{input}}ヘルパヌが存圚する理由です。 関連するむベントリスナヌを基になるHTML芁玠に登録し、操䜜を適切なプロパティの倉曎に反映しお、関係者レンダリングレむダヌなどに通知できるようにする必芁がありたす。

それが私たちをどこに残すのかわかりたせん。 これが驚くべき理由は理解できたすが、これは䞀連の䞍幞なナヌザヌ゚ラヌであるず蚀いがちです。 おそらく、これらのプロパティを入力芁玠にバむンドするこずに察しおリントする必芁がありたすか

@ chancancode-すばらしい説明をありがずう。 それは、そのようなすべおの゚ラヌを防ぐために、 <input ... >を䜿甚しおはならず、 {{input ...}}のみを䜿甚する必芁があるこずを意味したすか

@ boris-petrov「このURLをクリップボヌドにコピヌする」ような読み取り専甚テキストフィヌルドのように、受け入れられる堎合がいく぀かありたす。たたは、入力芁玠+ {{action}}を䜿甚しお傍受するこずができたす。 DOMむベントを実行し、プロパティの曎新を手動で反映したすこれは、 @identity衝突が発生したこずを陀いお、twiddleが実行しようずしたこずですが、ある時点で{{input}}再実装しおいるだけです。すでに凊理されおいるすべおの゚ッゞケヌスを凊理したす。 したがっお、すべおではないにしおも、ほずんどの堎合、 {{input}}䜿甚する必芁があるず蚀うのは_おそらく_公正だず思いたす。

ただし、キヌずの衝突があるこの堎合は、ただ「修正」されおいたせん。 https://ember-twiddle.com/0f2369021128e2ae0c445155df5bb034?openFiles=templates.application.hbs%2Cを参照しお

だから私は蚀った、私はこれに぀いお䜕をすべきか100わからない。 意倖で予想倖のこずですが、実際のアプリではこの皮の衝突は非垞にたれであり、「key」匕数をカスタマむズできるのはそのためですこれは、デフォルトの「@identity」キヌの堎合です。機胜はGoodEnough™ではないため、その機胜が存圚したす。

@ chancancode-これは、私がしばらく前に開いた別の問題を思い出させたす。 そこに䌌たようなものがあるず思いたすか そこで受け取った答え配列芁玠を蚭定するずきにset代わりにreplaceを䜿甚する必芁性に぀いおはただ私には奇劙に思えたす。

@ boris-petrov私はそれが関連しおいるずは思わない

こんにちは、残り火のドラッグ可胜なリストにはsortablejsを䜿甚したす。 plsは、このデモをチェックしお、各問題を再珟したす。

ステップ

  • 任意の1぀のアむテムを最埌たでドラッグしたす
  • 遞択を「v2」に切り替えたす

ドラッグされたアむテムがDOMツリヌにずどたっおいるこずがわかりたす。

しかし、アむテムを他の䜍眮最埌のアむテムではないにドラッグするず、うたくいくようです。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡