これは#7249に対処するためのものです。 このドキュメントでは、Reactがカスタム要素の属性とプロパティを処理するために使用できるさまざまなアプローチの長所と短所について概説しています。
Reactがカスタム要素にデータを渡そうとすると、常にHTML属性を使用して渡されます。
<x-foo bar={baz}> // same as setAttribute('bar', baz)
属性は文字列にシリアル化する必要があるため、このアプローチでは、渡されるデータがオブジェクトまたは配列である場合に問題が発生します。 そのシナリオでは、次のような結果になります。
<x-foo bar="[object Object]">
この回避策は、 ref
を使用してプロパティを手動で設定することです。
<x-foo ref={el => el.bar = baz}>
現在出荷されているカスタム要素の大部分は、公開されているすべての属性をバックアップするJavaScriptプロパティを自動的に生成するライブラリで記述されているため、この回避策は少し不必要に感じます。 また、バニラカスタム要素を手動で作成する場合は、この方法に従うことをお勧めします。 Reactのカスタム要素とのランタイム通信がデフォルトでJavaScriptプロパティを使用することを理想的に見たいと思います。
このドキュメントでは、これを実現するためにReactを更新する方法に関するいくつかの提案の概要を説明しています。
プロパティまたは属性を設定する必要があるかどうかを判断しようとするのではなく、Reactは常にカスタム要素にプロパティを設定できます。 Reactは、プロパティが要素に存在するかどうかを事前に確認しません。
例:
<x-foo bar={baz}>
上記のコードにより、Reactはx-foo
要素の.bar
プロパティをbaz
値に等しく設定します。
camelCasedプロパティ名の場合、ReactはtabIndex
などのプロパティに現在使用されているのと同じスタイルを使用できます。
<x-foo squidInk={pasta}> // sets .squidInk = pasta
このモデルは単純で明示的であり、Reactの「JavaScript中心のAPI to theDOM します。
PolymerやSkateなどのライブラリで作成された要素は、公開された属性をバックアップするためのプロパティを自動的に生成します。 これらの要素はすべて、上記のアプローチで「正しく機能する」はずです。 バニラコンポーネントを手動で作成する開発者は、HTML5要素( <video>
、 <audio>
など)の最新性(つまり、 <input>
ような奇妙なものでているためて属性をます。実装されています。
Reactがカスタム要素に属性を設定すると、HTMLの将来のバージョンで同様の名前の属性が出荷され、問題が発生するリスクが常にあります。 この懸念は仕様の作成者と話し合われましたが、問題に対する明確な解決策はありません。 属性を完全に回避すると(開発者がref
を使用して明示的に属性を設定する場合を除く)、ブラウザーがより良い解決策を思い付くまで、この問題を回避できます。
カスタム要素はページ上で遅延アップグレードでき、一部のPRPLパターンはこの手法に依存しています。 アップグレードプロセス中に、カスタム要素は、定義がロードされる前にそれらのプロパティが設定されていたとしても、Reactによって渡されたプロパティにアクセスし、それらを使用して初期状態をレンダリングできます。
Reactコンポーネントが相互にデータを渡すとき、それらはすでにプロパティを使用しています。 これにより、カスタム要素が同じように動作するようになります。
開発者が属性APIのみを持つバニラカスタム要素を手動で作成している場合は、コードを更新する必要があります。そうしないと、アプリが破損します。 修正は、 ref
を使用して属性を設定することです(以下で説明します)。
プロパティが優先されるように動作を変更することにより、開発者はカスタム要素に属性を明示的に設定するためにref
を使用する必要があります。
<custom-element ref={el => el.setAttribute('my-attr', val)} />
これは、開発者がプロパティを設定するためにref
を必要とする現在の動作の逆です。 開発者がカスタム要素に属性を設定する必要はめったにないので、これは合理的なトレードオフのように思われます。
このモデルがサーバー側のレンダリングカスタム要素にどのようにマッピングされるかは明確ではありません。 Reactは、プロパティが同様の名前の属性にマップされ、サーバー上でそれらを設定しようとすると想定できますが、これは防弾にはほど遠いため、キャメルケースのプロパティ->ダッシュケースの属性などのヒューリスティックが必要になる可能性があります。
実行時に、Reactはプロパティがカスタム要素に存在するかどうかを検出しようとする可能性があります。 プロパティが存在する場合、Reactはそれを使用します。存在しない場合、属性の設定にフォールバックします。 これは、Preactがカスタム要素を処理するために使用するモデルです。
擬似コードの実装:
if (propName in element) {
element[propName] = value;
} else {
element.setAttribute(propName.toLowerCase(), value);
}
可能な手順:
要素に定義済みのプロパティがある場合、Reactはそれを使用します。
要素に未定義のプロパティがあり、Reactがその要素にプリミティブデータ(文字列/数値/ブール値)を渡そうとしている場合、属性を使用します。
要素に未定義のプロパティがあり、Reactがその要素にオブジェクト/配列を渡そうとしている場合、その要素はプロパティとして設定されます。 これは、some-attr = "[objectObject]"が役に立たないためです。
要素がサーバー上でレンダリングされていて、Reactが要素に文字列/数値/ブール値を渡そうとしている場合、属性を使用します。
要素がサーバー上でレンダリングされていて、Reactが要素をオブジェクト/配列に渡そうとしている場合、要素は何もしません。
インターフェイスとして属性のみを使用するカスタム要素を作成することができます。 このオーサリングスタイルは推奨されていませんが、関係なく発生する可能性があります。 カスタム要素の作成者がこの動作に依存している場合、この変更は彼らにとって壊滅的ではありません。
要素のロード方法によっては、Reactがプロパティではなく属性を設定すると、開発者が混乱する可能性があります。
Sebastianは、 in
を使用してカスタム要素のプロパティの存在を確認すると、スーパークラス(HTMLElement)のプロパティを誤って検出する可能性があるという懸念を
このドキュメントで前述したグローバル属性との潜在的な競合も他にもあります。
Reactはカスタム要素に属性を設定し続けることができますが、開発者が代わりにプロパティを明示的に設定するために使用できる印章を提供します。 これは、Glimmer.jsで使用されています。
グリマーの例:
<custom-img @src="corgi.jpg" @hiResSrc="[email protected]" width="100%">
上記の例では、@ sigilは、 src
とhiResSrc
がプロパティを使用してカスタム要素にデータを渡し、 width
を属性文字列にシリアル化する必要があることを示しています。
Reactコンポーネントはすでにプロパティを使用して相互にデータを渡しているため、シジルを使用する必要はありません(使用した場合は機能しますが、冗長になるだけです)。 代わりに、JavaScriptプロパティを使用してカスタム要素にデータを渡すための明示的な命令として主に使用されます。
このアプローチを提案してくれたPreactの@developitへのh / t :)
既存のすべてのReact +カスタム要素アプリは、引き続き正確に機能します。 開発者は、新しいsigilスタイルを使用するようにコードを更新するかどうかを選択できます。
Glimmerと同様に、AngularとVueはどちらも、属性とプロパティを区別するために修飾子を使用します。
Vueの例:
<!-- Vue will serialize `foo` to an attribute string, and set `squid` using a JavaScript property -->
<custom-element :foo="bar” :squid.prop=”ink”>
角度のある例:
<!-- Angular will serialize `foo` to an attribute string, and set `squid` using a JavaScript property -->
<custom-element [attr.foo]="bar” [squid]=”ink”>
開発者は、 properties-if-availableアプローチのようなヒューリスティックに依存する代わりに、Reactに必要なものを正確に伝えることができます。
開発者はそれを使用する方法を教えられる必要があり、それが下位互換性があることを確認するために徹底的にテストされる必要があります。
印章は、同様の名前の属性を使用するように切り替える必要がありますか?
Reactは、作成者がデータを属性として明示的に渡すことを可能にする構文を追加する可能性があります。 開発者がこの属性オブジェクトを使用しない場合、JavaScriptプロパティを使用してデータが渡されます。
例:
const bar = 'baz';
const hello = 'World';
const width = '100%';
const ReactElement = <Test
foo={bar} // uses JavaScript property
attrs={{ hello, width }} // serialized to attributes
/>;
このアイデアは、もともとSkate.jsの作者である@treshugartによって提案され、 valライブラリに実装されています。
開発者は、 properties-if-availableアプローチのようなヒューリスティックに依存する代わりに、Reactに必要なものを正確に伝えることができます。
注:これはこのドキュメントの範囲外ですが、言及する価値があるかもしれません:)
問題#7901は、宣言型イベントハンドラーがカスタム要素に追加されたときに、Reactが合成イベントシステムをバイパスするように要求します。 カスタム要素のイベント名は任意の文字列であるため、任意の方法で大文字にすることができます。 今日の合成イベントシステムをバイパスするには、JSXからaddEventListener
イベント名をマッピングするためのヒューリスティックを考え出す必要があることも意味します。
// should this listen for: 'foobar', 'FooBar', or 'fooBar'?
onFooBar={handleFooBar}
ただし、構文が属性を許可するように拡張されている場合は、イベントも許可するように拡張することもできます。
const bar = 'baz';
const hello = 'World';
const SquidChanged = e => console.log('yo');
const ReactElement = <Test
foo={bar}
attrs={{ hello }}
events={{ SquidChanged}} // addEventListener('SquidChanged', …)
/>;
このモデルでは、変数名がイベント名として使用されます。 ヒューリスティックは必要ありません。
開発者はそれを使用する方法を教えられる必要があり、それが下位互換性があることを確認するために徹底的にテストされる必要があります。
コンポーネントがすでにattrs
またはevents
という名前のプロパティに依存している場合、それらを壊す可能性があります。
React 17の場合、(以前の提案の1つと同様に)段階的な変更を行い、この提案を後でより大きなリファクタリングのために検討するものとして位置付ける方が簡単な場合があります。
この提案は、Reactチームの@sophiebitsと@gaearonによって提供されました。
Reactは、要素の動作を構成オブジェクトにマップするカスタム要素を使用するための新しいAPIを作成できます。
擬似コードの例:
const XFoo = ReactDOM.createCustomElementType({
element: ‘x-foo’,
‘my-attr’: // something that tells React what to do with it
someRichDataProp: // something that tells React what to do with it
});
上記のコードは、指定した構成に応じてカスタム要素にデータを渡す方法を知っているプロキシコンポーネントXFoo
を返します。 カスタム要素を直接使用する代わりに、アプリでこのプロキシコンポーネントを使用します。
使用例:
<XFoo someRichDataProp={...} />
開発者はReactに彼らが望む正確な振る舞いを伝えることができます。
開発者は、オブジェクトの使用をオプトインするか、現在のシステムを引き続き使用できます。
この変更は新しいJSX構文を必要とせず、Reactの他のAPIのように感じます。 たとえば、PropTypes(独自のパッケージに移動されている場合でも)のアプローチはやや似ています。
ポリマーの紙入力要素には37のプロパティがあるため、非常に大きな構成が生成されます。 開発者がアプリで多くのカスタム要素を使用している場合、それは彼らが書く必要のある多くの構成に等しいかもしれません。
上記の点に関連して、各カスタム要素クラスは、その定義+構成オブジェクトサイズのコストを負担するようになりました。
注:これが正しいかどうかは100%わかりません。
コンポーネントが新しいプロパティを追加するマイナーバージョンリビジョンを実行するたびに、構成も更新する必要があります。 それは難しいことではありませんが、それはメンテナンスを追加します。 構成がソースから生成される場合、これは負担が少ないかもしれませんが、それは各Webコンポーネントライブラリの構成を生成するための新しいツールを作成する必要があることを意味する場合があります。
cc @sebmarkbage @gaearon @developit @treshugart @justinfagnani
長い間お読みいただき、お詫び申し上げますが、各オプションを徹底的に検討していることを確認したいと思いました。 私は自分の意見で物事をあまり偏らせたくないのですが、私が選択する立場にあるなら、私はオプション3を選ぶと思います。
オプション3は、下位互換性があり、宣言型で、明示的です。 フォールバックヒューリスティックを維持する必要はなく、他のライブラリはすでに同様のシジル/修飾子を提供しています。
長い間お読みいただき、お詫び申し上げますが、各オプションを徹底的に検討していることを確認したいと思いました。 私は自分の意見で物事をあまり偏らせたくないのですが、私が選択する立場にあるなら、私はオプション3を選ぶと思います。
オプション3は、下位互換性があり、宣言型で、明示的です。 フォールバックヒューリスティックを維持する必要はなく、他のライブラリはすでに同様のシジル/修飾子を提供しています。
私はオプション2とオプション3の中間にあり、Reactは過去に動作とAPIの変更を非常にうまく処理したと思います。 警告とドキュメントへのリンクを導入すると、開発者が内部で何が起こっているのかを理解するのに役立つ可能性があります。
オプション3は、その宣言型の性質のために魅力的に見えますが、JSXコードを読んでいる間、新しい開発者は、要素をレンダリングするときにReactが何をするかをすぐに知ることができます。
要素のロード方法によっては、Reactがプロパティではなく属性を設定すると、開発者が混乱する可能性があります。
カスタム要素の消費者は、この違いを理解する必要がありますか? それとも、カスタム要素の作成者にとってのみ重要ですか? 複雑な値やDOMからのプロパティの取得/設定をサポートする場合は、要素の作成者がHTMLで使用されるすべての属性(HTMLの使用からデータが渡される唯一の方法であるため)とプロパティを処理する必要があるようです。 作成者が最初に属性として何かを実装し、後で同じ名前のプロパティを追加して、より柔軟なデータ型をサポートし、属性に格納された値でプロパティをバックアップすることも可能です。
将来のHTMLElement属性およびプロパティとの名前の衝突は、バインディングアプローチに関係なくエラーにつながる可能性があるため、一般にWebコンポーネント標準の弱点のように思われます。
要素に未定義のプロパティがあり、Reactがその要素にオブジェクト/配列を渡そうとしている場合、その要素はプロパティとして設定されます。 これは、some-attr = "[objectObject]"が役に立たないためです。
値に基づいて異なる方法でバインドするのは混乱しているようです。 要素の作成者が値を処理するためのプロパティゲッター/セッターを指定していない場合、プロパティを設定すると、値が指定されなかったように要素が動作し、デバッグが困難になる可能性があります。
オプション3のもう1つの潜在的な欠点は、カスタム要素のコンシューマーが、要素が何かをプロパティとして実装したのか、属性として実装したのかを知る必要があることです。 Reactコンポーネントとカスタム要素を組み合わせて使用している場合、1つの構文を使用してReactプロップを設定し、別の構文を使用してカスタム要素のプロパティを設定すると混乱する可能性があります。
カスタム要素の消費者は、この違いを理解する必要がありますか? それとも、カスタム要素の作成者にとってのみ重要ですか?
ご指摘のとおり、要素の作成者は基になる値の属性とプロパティを定義し、両方からのデータを受け入れる必要があるため、これが実際には大きな問題であるとは思えません。 また、属性とプロパティの同期を維持する必要があることも追加します(したがって、一方を設定するともう一方が設定されます)。
将来のHTMLElement属性およびプロパティとの名前の衝突は、バインディングアプローチに関係なくエラーにつながる可能性があるため、一般にWebコンポーネント標準の弱点のように思われます。
私は同意しますが、これがReactがライブラリで回避しようとする必要があるものであるかどうかはわかりません。 カスタム要素仕様の一部として解決する必要がある問題のように感じます。 次回のTPAC基準会議の一環としてそれについて話し合うことができるかどうかがわかります。
要素定義プロパティはHTMLElementに追加される将来のプロパティをシャドウイングするため、プロパティの場合、これは悪いことではありません。 したがって、jsプロパティとしてカスタム要素にデータを渡す場合、それは引き続き機能します。 属性はグローバルであるため、主な問題は属性に関連しているようです。
値に基づいて異なる方法でバインドするのは混乱しているようです。 要素の作成者が値を処理するためのプロパティゲッター/セッターを指定していない場合、プロパティを設定すると、値が指定されなかったように要素が動作し、デバッグが困難になる可能性があります。
カスタム要素が遅延ロードされて「アップグレード」される場合、最初は未定義のプロパティがあります。 これは、それらの要素が引き続きデータを受信し、アップグレード後に使用できるようにすることで、そのユースケースに対処します。
確かに、作成者が値のゲッター/セッターを定義しない場合、これはあまり役に立ちません。 しかし、 my-attr=[object Object]
を持っていることも役に立ちません。 また、プロパティが本当に未定義なのか、それとも定義が遅延ロードされているだけなのかわからないため、プロパティを設定するのが最も安全なようです。
オプション3のもう1つの潜在的な欠点は、カスタム要素のコンシューマーが、要素が何かをプロパティとして実装したのか、属性として実装したのかを知る必要があることです。
カスタム要素の作成者にプロパティではなく属性を定義するように強制するものは何もないので、今日は基本的に同じボートに乗っていると思います。 したがって、Reactの現在のシステムからデータを受け取らないプロパティのみのAPIを持つ要素を持つことができ、jsプロパティを直接設定するためにref
を使用することを知る必要があります。
カスタム要素はプリミティブとして意図されているため、対応する属性とプロパティの作成を強制するものは何もありません。 しかし、私たちはベストプラクティスとしてそうすることを奨励しようと懸命に努力しており、今日私が知っているすべてのライブラリは、それらの属性のバッキングプロパティを作成します。
[編集]
前のポイントで述べたように:
複雑な値やDOMからのプロパティの取得/設定をサポートする場合は、要素の作成者がHTMLで使用されるすべての属性(HTMLの使用からデータが渡される唯一の方法であるため)とプロパティを処理する必要があるようです。
ユーザーがどのようにデータを要素に渡そうとするかがわからないため、とにかく属性とプロパティの対応が必要になります。 オプション3が出荷された場合、ほとんどの人は@
印章を使用してすべてをバインドするのが最も簡単であると想像します。 .prop
修飾子を公開しているので、今日Vueでカスタム要素を操作する方法です。
カスタム要素のコンシューマーは、要素が何かをプロパティとして実装したのか、属性として実装したのかを知る必要があります。
Robが私の意見で言ったように、これはReactが心配すべきことではありません。要素がどのように機能するかをユーザーに通知するのは、カスタム要素の作成者の責任です。
そして、それは実際に今日私たちがそれを行う必要がある方法です。たとえば、 <video>
要素について考えてみましょう。たとえば、要素をミュートしたり、コンポーネント内の現在の時刻を変更したりする必要があるとします。
muted
はブール属性として機能します
render() {
return (
<div className="video--wrapper">
<video muted={ this.state.muted } />
</div>
);
}
現時点では、ビデオ要素を指すref
を作成し、プロパティを変更する必要があります。
render() {
return (
<div className="video--wrapper">
<video ref={ el => this.video = el } muted={ this.state.muted } />
</div>
);
}
次に、イベントハンドラー、インスタンスメソッドを作成し、プロパティをDOM要素に手動で設定します。
onCurrenTimeChange(e) {
this.video.currentTime = e.value;
}
currentTime
は明らかにラッパーコンポーネントの状態であり、プロパティバインディングを使用すると、イベントハンドラーが必要になりますが、 JSX抽象化モデルはより宣言的であり、これだけのために参照は必要ありません。
render() {
return (
<div className="video--wrapper">
<video muted={ this.state.muted } @currentTime={ this.state.currentTime } />
</div>
);
}
私のポイントは、ネイティブ要素とカスタム要素のどちらに依存している場合でも、ドキュメントに基づいてそれらを回避する方法を知る必要があるということです。2番目の場合は、カスタム要素の作成者からのものである必要があります。
@cjorasch私の2セント:)
下位互換性を考慮する必要なしにこれをゼロから設計する場合、オプション1はReactの「JavaScript中心のAPI to theDOM
サーバー側のレンダリングに関して、カスタム要素のプロパティを属性にマップする方法をReactに通知するアプリケーションコード用のAPIを提供することで、この問題を解決できますか? Reactがプラットフォーム定義の属性に対してすでに維持しているマップと同様ですか? このAPIは、カスタム要素名ごとに1回だけ呼び出す必要があり(インスタンスごとではありません)、属性と1:1で直接対応しないプロパティに対してのみ呼び出す必要があります。これは、比較的まれなことです。
しかし、これがあまりにも大きな変化であることが懸念される場合は、オプション3もかなり魅力的だと思います。 印章がプロパティを意味する場合、それはすでにJavaScriptのプロパティアクセサーであるため、「。」をお勧めします。 ただし、アプリケーションでカスタム要素が使用されるすべてのインスタンスに、属性を使用する場合とプロパティを使用する場合の関係を把握させるのは残念なことだと思います。 オプション1について私が好むのは、属性マップへのプロパティが必要な場合でも、そのマッピングコードをすべてのJSXの使用法から分離できることです。
カスタム要素が遅延ロードされて「アップグレード」される場合、最初は未定義のプロパティがあります。 これは、それらの要素が引き続きデータを受信し、アップグレード後に使用できるようにすることで、そのユースケースに対処します。
多分私はアップグレードプロセスを理解していません。 要素には通常、クラスプロトタイプでゲッター/セッターとして定義されたプロパティがあります。 propName in element
をチェックすると、プロパティ値がまだ定義されていない場合でも、ゲッター/セッターが存在するため、trueが返されます。 アップグレード中に、プロパティ値は一時的なインスタンスに設定され、遅延読み込みが完了すると後で実際のインスタンスにコピーされますか?
アップグレードは、カスタム要素がそのクラスを受け取るプロセスです。 それ以前は、そのクラスのインスタンスではないため、プロパティのゲッター/セッターは使用できません。
@jeremenichelli
ミュートはブール属性として機能します
チェックしたばかりで、MDN:Pに文書化されていないようですが、対応するプロパティもあります。
現時点では、ビデオ要素を指す参照を作成し、プロパティを変更する必要があります。
たまに、最新のHTML要素でプロパティのみのAPIに遭遇することがあります。 currentTime
は高頻度で更新されるため、HTML属性に反映しても意味がありません。
私のポイントは、ネイティブ要素とカスタム要素のどちらに依存している場合でも、ドキュメントに基づいてそれらを回避する方法を知る必要があるということです。
はい、残念ながら、万能の属性/プロパティルールはありません。 しかし、一般的に言って、開発者が特別な場合に属性を使用できるように、プロパティに大きく依存して構文を提供できると思います。
@robdodsonはい、ミュートされたプロパティについても知っていました😄私はこれら2つを使用して、あなたが言及したように、すでに_実際には_万能のルールがないことを証明しました。
ネイティブ要素とカスタム要素の両方に関するドキュメントに依存する必要があるため、この決定を気にしないでください。
最後のコードスニペットを書いている間、私はプロパティバインディングが好きでしたが💟
@effulgentsia
ただし、アプリケーションでカスタム要素が使用されるすべてのインスタンスに、属性を使用する場合とプロパティを使用する場合の関係を把握させるのは残念なことだと思います。
しかし、これは今日すでに当てはまると思います。 主要なカスタム要素ライブラリ(ポリマー、スケート、場合によっては他のライブラリ)は、公開されているすべての属性のバッキングプロパティを自動的に作成するため、開発者はカスタム要素のすべてのプロパティに印章を使用できます。 属性の使用に切り替える必要があるのは、おそらくまれなことです。
@cjorasch
RE:アップグレード。 @effulgentsiaが述べたように、ページにカスタム要素を<x-foo>
は、最初はHTMLElement
のインスタンスになり、後でその定義をロードすると、「アップグレード」されてXFoo
クラスのインスタンスになります。 この時点で、すべてのライフサイクルコールバックが実行されます。 この手法は、Polymer StarterKitプロジェクトで使用します。 このようなもの:
<app-router>
<my-view1></my-view1>
<my-view2></my-view2>
</app-router>
上記の例では、ルーターが変更されるまで、 my-view2
の定義をロードしません。
アップグレードする前に要素にプロパティを設定することは完全に可能であり、定義が読み込まれると、要素はライフサイクルコールバックの1つでそのデータを取得できます。
開発者は、カスタム要素のすべてのプロパティに印章を使用できます
開発者がそれを始めた場合、あなたが「しなければならない」という理由でプロパティを使用することと「できる」という理由でプロパティを使用することをどのように区別しますか? そして、それはサーバー側のレンダリングに必要な差別化ではありませんか?
開発者がそれを始めた場合、あなたが「しなければならない」という理由でプロパティを使用することと「できる」という理由でプロパティを使用することをどのように区別しますか?
申し訳ありませんが、多分私はそれを間違って言いました。 私は、開発者が最も一貫した結果をもたらすため、シギルを使用する可能性が高いことを意味しました。 これを使用して、プリミティブデータまたはオブジェクトや配列などのリッチデータを渡すことができ、常に機能します。 属性は初期構成でより多く使用される傾向があるため、実行時にプロパティを操作する方が、属性を操作するよりも一般的に好まれると思います。
そして、それはサーバー側のレンダリングに必要な差別化ではありませんか?
サーバー上で、シジルが属性の設定にフォールバックする場合があります。
サーバー上で、シジルが属性の設定にフォールバックする場合があります。
印章の理由が、ビデオのcurrentTimeなど、属性として存在しないプロパティである場合、それは機能しないと思います。
「できる」という理由でプロパティを使用することと、「しなければならない」という理由でプロパティを使用することを区別する
属性またはプロパティを最適化として使用することを選択する理由(たとえば、SSRが属性を優先するのか、クライアント側のレンダリングがプロパティを優先するのか)と、属性のみまたはのみとして存在するものとでは、まったく異なる理由があるため、この区別は重要だと思います。プロパティ。
サーバー側のレンダリングに関して、カスタム要素のプロパティを属性にマップする方法をReactに通知するアプリケーションコード用のAPIを提供することで、この問題を解決できますか?
具体的には、次のような提案をしています。
ReactDOM.defineCustomElementProp(elementName, propName, domPropertyName, htmlAttributeName, attributeSerializer)
例:
// 'muted' can be set as either a property or an attribute.
ReactDOM.defineCustomElementProp('x-foo', 'muted', 'muted', 'muted')
// 'currentTime' can only be set as a property.
ReactDOM.defineCustomElementProp('x-foo', 'currentTime', 'currentTime', null)
// 'my-attribute' can only be set as an attribute.
ReactDOM.defineCustomElementProp('x-foo', 'my-attribute', null, 'my-attribute')
// 'richData' can be set as either a property or an attribute.
// When setting as an attribute, set it as a JSON string rather than "[object Object]".
ReactDOM.defineCustomElementProp('x-foo', 'richData', 'richData', 'richdata', JSON.stringify)
プロパティにしかなり得ないもの( htmlAttributeName
がnullの場合)の場合、SSRはレンダリングをスキップして、クライアント上でハイドレイトします。
属性にしかなり得ないもの( domPropertyName
がnullの場合)の場合、Reactは現在v16のようにsetAttribute()
を呼び出します。
両方になり得るものについては、Reactは最適な戦略を選択できます。 おそらくそれは、常にクライアント側のプロパティとして設定することを意味しますが、サーバー側の属性として設定します。 おそらく、最初に要素を作成するときに属性として設定することを意味しますが、後でvdomからパッチを適用するときにプロパティとして設定することを意味します。 おそらく、値がプリミティブ型の場合にのみ属性として設定することを意味します。 理想的には、Reactは、内部実装の詳細として必要なときにいつでも戦略を変更できる必要があります。
Reactが、 defineCustomElementProp()
が呼び出されておらず、HTML仕様でグローバルプロパティまたは属性として定義されていない小道具に遭遇した場合、Reactはいくつかのデフォルトロジックを実装できます。 たとえば、おそらく:
ただし、いずれの場合も、これを個別のAPIに保持することで、JSXオブジェクトとprops
オブジェクトは、Reactコンポーネントや非カスタムHTML要素の場合と同様に、クリーンに保たれ、単一の名前空間内に保持されます。
過度のコメントをお詫び申し上げますが、上記の提案には、共有したい別のメリットがあると思いました。
これらのReactDOM.defineCustomElementProp()
呼び出しは、カスタム要素の作成者が管理するJSファイル(カスタム要素が管理/配布される場所と同じリポジトリ内)で提供できます。 プロパティ/属性が厳密に1:1で対応しているカスタム要素には必要ありません。これは、この号の背景ステートメントによると、とにかく推奨事項であり、大多数の場合です。 したがって、この推奨事項に従わないカスタム要素の作成者のみがReact統合ファイルを提供する必要があります。 作成者がそれを提供しない場合(たとえば、カスタム要素の作成者がReactを気にしないため)、Reactアプリ内でそのカスタム要素を使用する人々のコミュニティは、その統合ファイルを格納するための中央リポジトリを自己編成できます。
このような集中化の可能性は、カスタム要素のすべてのユーザーが常に印章で明示する必要があるソリューションよりも望ましいと思います。
オプション3が私の好みですが、それは大きな重大な変更です...逆はどうですか? 属性には小道具ではなく接頭辞がありますか?
Reactの印章、私はそれについてどう感じているのかわかりません。 JSX仕様は、特に下位互換性による不規則性に依存したり、ブラウザの仕様に過度に依存したり依存したりすることなく、普遍的であると見なす必要があります。 obj[prop] = value
とobj.setAttributes(props, value)
動作が異なるのは残念ですが、ブラウザーAPI全体を見ると、驚くことではありません。 @ : []
は、実装の詳細を表面に漏らし、JavaScript中心のアプローチと矛盾します。 したがって、次のことを行う仕様がない限り、それは悪い考えだと思います: const data = <strong i="8">@myFunction</strong> // -> "[object Object]"
Webコンポーネントに依存する必要がある場合は、セマンティクスがReactとJSXから隠されていて、重大な変更が導入されていないことを確認できれば幸いです。 すべてのオプションから、 ref => ...
をそのままにしておくことは私にとって有利なようです。 ref
は、オブジェクトにアクセスするために特別に設計されています。 そして、少なくとも開発者は何が起こっているのかを正確に知っています。印章の漏れはなく、既存のプロジェクトを壊す可能性のある新しい属性もありません。
@LeeCheneler
オプション3が私の好みですが、それは大きな重大な変更です...逆はどうですか? 属性には小道具ではなく接頭辞がありますか?
なぜそれは重大な変化になるのでしょうか? デフォルトである属性の現在の動作はそのままです。 印章はオプトインであり、開発者はそれを使用して、現在ref
を使用してデータをJSプロパティとしてカスタム要素に渡すコード内のスポットを置き換えます。
@drcmda
既存のプロジェクトを壊す可能性のある新しい属性もありません。
これが何を意味するのか明確にできますか?
参考までに、ディスカッションをフォローしている人のために、Reactチームのメンバーによって提案された5番目のオプションでRFCを更新しました。
@robdodson
私はこれを参照していました:
オプション4:属性オブジェクトを追加する
短所
それは重大な変化かもしれません
オプション5は私たちにとって最も安全なようです。 エコシステムはまだ「それを理解する」段階にあるので、今すぐ「暗黙の」APIについて決定する必要なしに機能を追加することができます。 数年後にはいつでも再訪できます。
ポリマーの紙入力要素には37のプロパティがあるため、非常に大きな構成が生成されます。 開発者がアプリで多くのカスタム要素を使用している場合、それは彼らが書く必要のある多くの構成に等しいかもしれません。
私の印象では、Reactのカスタム要素ユーザーは、アプリ固有の動作/カスタマイズのために、いずれにせよ、いくつかのカスタム要素をReactコンポーネントにラップしたいと思うでしょう。 すべてがすでにある場合は、このケースのためのよりよいの移行戦略であるコンポーネント、例えばリアクト
import XButton from './XButton';
そしてそれはたまたまによって生成されます
export default ReactDOM.createCustomElementType(...)
これにより、Reactコンポーネントを、任意の時点でカスタム要素を使用する(または使用しない)カスタムコンポーネントに置き換えることができます。
したがって、相互運用ポイントでReactコンポーネントを作成する場合は、そのための強力なヘルパーを提供することもできます。 また、使用するカスタム要素の構成を共有する可能性もあります。
そして最終的には、エコシステムが安定していることがわかった場合、構成なしのアプローチを採用できます。
ここでの次のステップは、すべての一般的なユースケースを満たすために構成がどのように見えるかについての詳細な提案を書くことだと思います。 カスタム要素+ Reactユーザーにとっては十分に説得力があるはずです。なぜなら、それが一般的なユースケース(イベント処理など)に答えない場合、機能が冗長性を相殺するのに十分な利点を提供しないという状況に陥ってしまうからです。 。
私の以前のコメントから構築し
const XFoo = ReactDOM.createCustomElementType('x-foo', {
propName1: {
propertyName: string | null,
attributeName: string | null,
attributeSerializer: function | null,
eventName: string | null,
}
propName2: {
}
...
});
その場合、ロジックは、XFooインスタンス上の各Reactプロップに対して次のようになります。
eventName
がnullでない場合は、prop値を呼び出すイベントハンドラーとして登録します(関数であると想定されます)。propertyName
がnullでない場合は、elementプロパティをprop値に設定します。attributeName
がnullでない場合は、element属性を文字列化されたprop値に設定します。 attributeSerializer
がnullでない場合は、それを使用してprop値を文字列化します。 それ以外の場合は、 '' + propValue
ます。ポリマーの紙入力要素には37のプロパティがあるため、非常に大きな構成が生成されます。
設定は外れ値の小道具にのみ必要であることを提案したいと思います。 構成に含まれていなかったXFooインスタンス上の小道具の場合、デフォルトで次のようになります。
eventName: the prop name,
propertyName: the prop name,
attributeName: camelCaseToDashCase(the prop name),
あるいは、イベントを別の名前空間に保持することは理にかなっています。その場合、最後のコメントからeventName
に関係するすべてのものを削除し、代わりにイベントを次のように登録します。
<XFoo prop1={propValue1} prop2={propValue2} events={event1: functionFoo, event2: functionBar}>
</XFoo>
@gaearon @effulgentsiaオプション1とオプション5の組み合わせについてどう思いますか?
オプション1を使用すると、カスタム要素のカジュアルユーザーが豊富なデータを簡単に渡すことができます。 アプリを作成していて、いくつかのカスタム要素を使用したいというシナリオを想像しています。 私はそれらがどのように機能するかをすでに知っており、それらの構成を書きたいほど投資していません。
オプション5は、アプリ全体で紙の入力のようなものを使用し、そのAPI全体をチームの全員に公開したい人向けです。
オプション1のSSRの場合、サーバーでレンダリングする場合、ヒューリスティックは常に属性を使用できます。 camelCaseプロパティは、ダッシュケース属性に変換されます。 これは、Webコンポーネントライブラリ全体でかなり一般的なパターンのようです。
option1 + option5の組み合わせのアイデアがとても好きです。 ほとんどのカスタム要素の意味:
<x-foo prop1={propValue1}>
期待どおりに機能します。prop1は、クライアント側のプロパティおよびサーバー側の(ダッシュケースの)属性として設定されます。
そして、上記が自分に合わないものについては、option5に切り替えることができます。
React 16の動作方法からは、大きな変化になるでしょう。 その破損を経験した人(たとえば、プロパティに裏付けられていない属性を持つカスタム要素を使用していた)の場合、option5に切り替えることができますが、それでも破損です。 それが許容できるかどうかを判断するのはReactチームに任せます。
ああ、これは私が電車の中でこれをすばやく読むことで得られるものです@ robdodson🤦♂️ ...今はオプション3のファンではありません🤔私はそれを小道具のオールインとして読んだので、ためらいました。
オプション5は合理的で簡単なようです。
@effulgentsiaが向かっているところが
const XFoo = ReactDOM.createCustomElementType('x-foo', {
propName1: T.Attribute,
propName2: T.Event,
propName3: T.Prop
})
または、1つの小道具で複数のタイプをサポートすることは価値がありますか?
@effulgentsia :私はこの流れに躊躇するでしょう:
値が関数の場合:
eventName:小道具名、
そうしないと:
propertyName:小道具名、
attributeName:camelCaseToDashCase(小道具名)、
関数propをデフォルトでイベントに設定したくないと思いますが、propertyNameとattributeNameの両方を適切に割り当てていますか? 上記の質問を模倣するために、両方をサポートするのはいつですか? 🙂
@LeeCheneler :
問題の概要のオプション1の長所からの引用:
PolymerやSkateなどのライブラリで作成された要素は、公開された属性をバックアップするためのプロパティを自動的に生成します。 これらの要素はすべて、上記のアプローチで「正しく機能する」はずです。 バニラコンポーネントを手動で作成する開発者は、HTML5要素(
<video>
、<audio>
など)の最新性(つまり、<input>
ような奇妙なものでているためて属性をます。実装されています。
これが、propertyNameとattributeNameの両方を割り当てることが賢明な理由です。これは、ベストプラクティスに従う要素の実際のケースを反映しているためです。 そして、Reactにそれを認識させることで、Reactは、クライアント側のレンダリングにプロパティを使用したり、サーバー側のレンダリングに属性を使用したりするなど、状況に基づいてどちらを使用するかを決定できます。 ベストプラクティスに従わず、対応するプロパティのない一部の属性や対応する属性のない一部のプロパティを持つカスタム要素の場合、Reactはそれを認識する必要があります。これにより、SSRおよびプロパティ中に属性のないプロパティがレンダリングされなくなります。 -less-属性は、クライアント側のレンダリング中にsetAttribute()で設定できます。
あなたの提案では、それは次のようなビット結合フラグによって行われる可能性があります。
propName1: T.Property | T.Attribute,
ただし、それでは、属性名がプロパティ名と異なることを表現する方法は提供されません(たとえば、キャメルケースからダッシュケース)。 また、SSR中にリッチオブジェクトを属性にシリアル化する方法を表現する方法も提供しません(「[オブジェクトオブジェクト]」の現在の動作は役に立ちません)。
関数の小道具をデフォルトでイベントに設定したくないと思います
ええ、私もそれに同意すると思いますので、フォローアップコメントです。 それで私の躊躇を検証してくれてありがとう!
これが
const XFoo = ReactDOM.createCustomElementType('x-foo', {
UNREFLECTED_ATTRIBUTES: [
'my-attr-1',
'my-attr-2',
],
UNREFLECTED_PROPERTIES: [
'myProp1',
'myProp2',
],
REFLECTED_PROPERTIES: {
// This is default casing conversion, so could be omitted.
someVeryLongName1: 'some-very-long-name-1',
// In case anyone is still using all lowercase without dashes.
someVeryLongName2: 'someverylongname2',
// When needing to define a function for serializing a property to an attribute.
someRichData: ['some-rich-data', JSON.stringify],
},
});
上記のコードコメントによると、すべてのリフレクトプロパティを定義する必要はなく、属性名がダッシュケースバージョンであるリフレクトプロパティとして自動的に定義されていないものはすべてデフォルトにすることを強くお勧めします。
理にかなっています@effulgentsia👍
私はあなたの2番目の例が好きですが、より多くのタイプが追加された場合、alaイベント+意味があるかもしれないものは何でも組み合わせ爆発に開かれていませんか?
- UNREFLECTED_ATTRIBUTES
- UNREFLECTED_PROPERTIES
- UNREFLECTED_EVENTS
- REFLECTED_PROPERTIES_ATTRIBUTES
- REFLECTED_PROPERTIES_EVENTS
- REFLECTED_ATTRIBUTES_EVENTS
- REFLECTED_PROPERTIES_ATTRIBUTES_EVENTS
...
とにかくイベントを小道具や属性と混ぜたくないと思いますが🤔属性と小道具だけがおそらく模倣したいものです。
ここには、ReactコミュニティとWebコンポーネントコミュニティの両方がベストプラクティスに沿って調整する機会があると思います。 ここで意見を持っているReactは、その意見が広範に採用され、重みがあるため、カスタム要素の作成者が正しい方向に導かれるのに大いに役立ちます。
オプション4の実装を作成しましたが、属性とイベントをプロパティから分離する必要があることに常に追いついています。 理想的には、オプション1をお勧めします。実際には、エスケープハッチを備えたオプション2をお勧めします。
オプション1は理想的ですが、対応するプロパティ(aria / data)を持たない属性の種類が多いため、これらの周りに追加のヒューリスティックが必要になります。また、要素に属性が必要なエッジケースがある場合は、プロパティですが、何らかの理由で実装しないでください。 これは慎重に検討する必要があるオプションだと思いますが、長期的には実行可能かもしれません。
オプション2は、重大な変更ではないため、推奨されます。 これは、インスタンスが作成される前に(またはプロパティが設定される前にロードされる)カスタム要素定義が登録されているすべての状況で機能します。 このオプションの先行技術はPreact(cc @developit)であり、これまでのところうまく機能しています。 この道を進むと、Reactバリアントの成功によって証明された、適度に堅牢で壊れない実装が得られ、ほとんどの状況で機能します。 どちらかといえば、それはReactに短期的な解決策を与え、より良い解決策は長期的に評価されます。
私たちがカバーされていないことをカスタム要素の定義及び任意の他の繰延ロード- -状況(?状況s)は、それが動作しないためにどのようなエスケープハッチインクリメンタルDOMを行っているが、実施することができます。 これは@effulgentsiaが提案しているものと似ていx
拡張する方が適切です。 消費者がカスタム要素ごとにそれを実行したい場合でも、それは単なる機能であるため、実行できます。 これにより、Reactは意見を持ち、ハッチを回避し、すべてのエッジケースの責任を消費者に引き渡すことですべてのユースケースを満足させることができます。 これは、Preactでの実装について@developitと以前に話し合ったことでもあります。 ここでのPreact / React間の調整は大きな勝利になります。
将来のHTML属性に関する懸念については、これは私たちが解決できないことなので、ここで私たち自身がそれに巻き込まれるべきではないと思います。
これらの
ReactDOM.defineCustomElementProp()
呼び出しは、カスタム要素の作成者が管理するJSファイルで提供できます。
これにより、カスタム要素の実装がライブラリ固有の実装(この場合はReact)に関連付けられます。 私の意見では、これはカスタム要素の作成者の負担が大きすぎます。 さらに、Reactを使用しない著者にとって、定義を出荷するように説得することは、誰も望まない政治的議論に入ります。
ユーザーが実際に使用するプロパティ/属性のみを使用してカスタム要素のユーザーによるこのようなAPIの呼び出しを定義すると、維持するコードが少なくなり、表現力が高まります。
ライブラリの作成者がReactを使用しない場合でも、これらのWebコンポーネントのクライアントがプロパティ構成を一度定義してから使用する方がUXとして優れていると私は主張しています。
プロパティを必要とするWebコンポーネントを初めて使用するときは、印章を追加するのと同じくらい難しいですが(より冗長ですが、より明示的です)、それについて考える必要がないため、その後の使用が簡単になります。そのコンポーネントのすべてのコールサイト。 どちらの場合も、新しいWebコンポーネントを採用するときにプロパティ/属性の違いを理解する必要がありますが、単一の共有構成では、同じアプリ内のそのコンポーネントのすべてのユーザーがそれについて考える必要はありません。
その構成でプロパティ名を再マッピングして、より多くのReact-idiomatic名を作成できるようにする可能性があります。 XFooを必要な高度な変換ロジックを実行するカスタムReactコンポーネントに置き換えるだけでよいため、より洗練されたラッパーへのアップグレードパスもスムーズになります。
基本的に:コンポーネントを使用するたびにプロパティの構成について考える必要がない場合は、そのアプローチをお勧めします。 そのため、オプション5を提案しました。同じように柔軟性がありながら、3や4よりも人間工学的だと思います。
オプション1と2は、サーバーレンダリング(HTML生成)ではうまく機能しません。また、オプション2は、既存の属性と同じ名前のプロパティを追加することが重大な変更であるWebコンポーネントの作成者にアップグレードの危険をもたらします。 SSRが役に立たないと判断した場合、オプション1はReactの観点からはかなり魅力的です。 ただし、実際に十分に包括的であるかどうかはわかりません。コンポーネントの作成者は、プロパティを介してすべてを公開しますか?
@treshugartは、バイクシェディングに深く
申し訳ありませんが、 @ sophiebitsはあなたの返信を見ています。 何度か読んだ後、いくつかの点に答えたいと思いますが、これにすばやく答えたいと思います。
ただし、実際に十分に包括的であるかどうかはわかりません。コンポーネントの作成者は、プロパティを介してすべてを公開しますか?
PolymerまたはSkateで構築されたコンポーネントはすべて、プロパティを介してすべてを公開します。 まれな外れ値がいくつかあるかもしれませんが(おそらくスタイリングなどのためだけに属性を設定する)、そうでなければ、物事は常にプロパティによって支えられていると思います。 実稼働中のWebコンポーネントの大部分は、これら2つのライブラリのいずれかを使用して構築されていると確信しています。
誰かがバニラWebコンポーネントを手動で作成している場合、プロパティを介してすべてを公開するように強制するものは何もありませんが、ベストプラクティスのドキュメントと例でそうすることをお勧めします。
その価値については、属性の使用を強制するものもありません。 カスタム要素定義は単なるクラスであるため、開発者は好きなことを行うことができます。 しかし実際には、ほとんどの人は、PolymerやSkateのような抽象化を使用してコンポーネントをミントすることを好むため、プロパティAPIを無料で入手しています。
おそらく、最善のアプローチは、常にクライアント側でプロパティを実行し、アプリでSSRをサポートしたい人のために、プリミティブプロパティ名から属性名へのオプション5スタイルの構成マップをサポートすることです。
@sophiebits :属性名を使用してReactアプリを作成した人にとっては
<x-foo long-name={val} />
しかし、propnameにダッシュがない場合は「doproperties」、ダッシュがない場合は「doattributes」のルールはどうでしょうか。
@robdodson :longName
プロパティを持つlongname
属性ですか? これは実際には、組み込みのHTML要素とグローバル属性(たとえば、 contenteditable
=> contentEditable
)を使用したはるかに一般的なパターンのようですが、現在十分に推奨されているかどうかはわかりません。ポリマーとスケートのおかげでカスタム要素属性のために。 それでも問題が解決しない場合は、既存のJSXで次のことを行ってください。
<x-foo longname={val} />
プロパティがlongName
場合、プロパティセットとして失敗します。
@effulgentsia私はSkateについてのみ話すことができますが、HTMLを作成する場合にのみ、属性APIを使用することをお勧めします。HTMLは、すべての目的と目的で、サーバーレンダリングとして分類することもできます。 JSを介して何かをしている場合は、小道具を設定する必要があります。 props
APIは、属性から一方向の同期/逆シリアル化を自動的に実行し、プロパティ名をダッシュケースで囲むことによって属性名を取得します(camelCaseはキャメルケースになるなど)。 この動作は全体として構成可能ですが、ベストプラクティスは前述のとおりにすることをお勧めします。
多くの人が述べているように、小道具はSSRを困難にし、これは有効な懸念事項です。 ほとんどの人がオプション1を好むように思われるので、フォールバック/マッピングを提供しながら、クライアントに小道具を設定するという@sophiebitsの提案を推し進めようとしていますか? これは、属性がサーバーに設定されることを意味すると思いますか?
例のために、ここにいますが、その実装は、サーバーからのスケートとクライアント(および任意のカスタム要素の状態や小道具の上に運ぶ実装する方法renderedCallback()
とprops
および/またはstate
セッター。カスタム要素レベルで行うのは簡単です。Reactがサーバーに属性を設定する道を進んだ場合、水分補給は基本的に同じです。スケートコンポーネントの作成者は、実際には何もする必要はありません。 'dはすでにそれらの逆シリアル化ロジックを提供しています。
@robdodsonインクリメンタルDOMが実行しているのと同様のことを実行します。 これは次のようになります。
const isBrowser = true; // this would actually do the detection
const oldAttributeHook = ReactDOM.setAttribute;
// This is much like the IDOM impl but with an arguably more clear name.
ReactDOM.setAttribute = (element, name, value) => {
// This is essentially option 2, but with the added browser check
// to keep attr sets on the server.
if (isBrowser && name in element) {
element[name] = value;
} else {
oldAttributeHook(element, name, value);
}
};
@sophiebits
オプション2は、既存の属性と同じ名前のプロパティを追加することが重大な変更であるWebコンポーネントの作成者にアップグレードの危険性ももたらします。
プラットフォームでの属性の動作を考えると、これは避けられないかもしれないと思います。 カスタム要素をSSRするため、属性に書き込む必要がある場合は、プラットフォームが将来同様の名前の属性を出荷するリスクもあります。 @treshugartが前に
それがオプション2についてあなたの考えをまったく変えるかどうかはわかりません😁しかし、オプション2にはいくつかの素晴らしいボーナスがあり、Preactが実際にそれを証明しているように見えるので、私はそれについて言及したいと思いました。
おそらく、最善のアプローチは、常にクライアント側でプロパティを実行し、アプリでSSRをサポートしたい人のために、プリミティブプロパティ名から属性名へのオプション5スタイルの構成マップをサポートすることです。
+1、私はこの方向に向かって進み続けることを支持しています。
@effulgentsia
属性名を使用してReactアプリを作成した人にとっては重大な変更であるという点を除けば、これは素晴らしいアイデアだと思います。
オプション2はそれを解決します:)
それ以外の場合は、ダッシュケースの属性をキャメルケースのプロパティにマップするオプション1と組み合わせたヒューリスティックが必要になる可能性があります。
しかし、propnameにダッシュがない場合は「doproperties」、ダッシュがない場合は「doattributes」のルールはどうでしょうか。
名前にダッシュがある場合、 Preactlong-name
がin
チェックに合格しないため、属性(ソース)にフォールバックするためだと思います。
私は個人的にこの振る舞いが好きですが、属性の設定と将来の競合の可能性の領域に戻るので、 @ sophiebitsを考慮に入れる必要があると思います。
ダッシュを含めずに、対応するプロパティとは異なる属性のケーシングを持つカスタム要素フレームワークまたはプラクティスを知っていますか?
私が知っていることではありません。 ダッシュは、図書館がキャメルケースの場所を知るための簡単な方法です。 バニラWebコンポーネントを手動で作成している場合は、 longname/longName
を実行でき、オプション2のみを使用すると、 longname
プロパティが見つからないため節約できますが、以前に使用されていたものにフォールバックします。 longname
属性。
その価値については、最後の手段として、Preactが属性を設定する前に認識しないプロパティに対してtoLowerCase()
を呼び出すように見えます。 したがって、 <x-foo longName={bar}/>
をSSRしている場合は、 longname=""
属性にも適切にフォールバックします。
@treshugart
フォールバック/マッピングを提供しながら、クライアントに小道具を設定するという@sophiebitsの提案を推し進めようとしているのではないでしょうか。 これは、属性がサーバーに設定されることを意味すると思いますか?
はい、そしてはい。
インクリメンタルDOMが行っているのと同じようなことをします
すべての要素(またはそれらの基本クラス)がこれを混ぜ合わせる必要があるという考えはありますか?
ところで、議論に参加し続けてくれてありがとう、私はそれがかなり長くなっていることを知っています❤️
https://github.com/facebook/react/issues/11347#issuecomment -339858314の最後の例を理解できるかどうかはわかりませんが、このようなグローバルなオーバーライド可能なフックを提供する可能性はほとんどありません。
@gaearon Treyは、正味の変更をモンキーパッチとして表示していたと思います。おそらく、ReactDOM実装自体に書き込まれるでしょう。
最近のコメントに基づいて、皆さんはこの提案についてどう思いますか?
BCの場合、Reactで小文字のカスタム要素がどのように機能するかについては何も変更しないでください。 言い換えれば、 <x-foo ... />
ようなJSXは、React 17でも16と同じように機能し続けます。または、_マイナー_バグ修正が必要な場合は、別の問題を開いてそれらについて話し合います。
構成のないAPIを追加して、より優れたカスタム要素セマンティクスを備えたReactコンポーネントを作成します。 例: const XFoo = ReactDOM.customElement('x-foo');
。
上で作成したコンポーネントには、次のセマンティクスを使用します。
children
、 ref
、その他?)であるXFooのプロップには、通常のReactセマンティクスを適用します(属性またはプロパティとして設定しないでください)。カスタム要素のDOMノード上)。data-*
およびaria-*
)については、それらがdiv
にある場合にReactが行うのと同じことをそれらの小道具で行います。 <XFoo data-x={} className={} contentEditable={} />
の小道具をDOMノードに適用する方法は、 <div data-x={} className={} contentEditable={} />
(クライアント側とSSRの両方)の場合と同じである必要があります。XFooの他のすべての小道具については、クライアント側でレンダリングするときに、プロパティとしてDOMノードに設定します。 SSRの場合、値がプリミティブの場合は、属性としてレンダリングします。 プリミティブでない場合は、レンダリングをスキップして、ハイドレーション中にクライアント側のプロパティとして設定します。 属性としてのSSRレンダリングの場合、camelCaseToDashCaseの名前。
上記の#2のAPIを介して作成されたコンポーネントの場合、イベントリスナーに使用する小道具名を予約します。 例: 'events'
または'eventListeners'
。 または、これらの潜在的なカスタム要素プロパティ名と競合したくない場合は、 '_eventListeners'
または'EventListeners'
です。 ReactDomによって作成されたXFoo
実装は、これらのイベントリスナーをDOMノードに自動的に登録します。
エッジケースの場合(たとえば、上記の実装が望ましくない、または十分でないカスタム要素を使用する場合)、アプリ開発者は独自のReactコンポーネントを実装して、必要な特別なことを行うことができます。 つまり、 ReactDOM.customElement()
を使用する必要はなく、拡張することもできます。
上記の行動のすべてをしたいが、そのJSXは小文字のカスタム要素名(使用したい人のための<x-foo />
の代わりに<XFoo />
HTMLを書くことに慣れて人々が好むことを同様の理由のため、 <div>
が<Div>
<div>
超える場合、React.createElement()にモンキーパッチを適用できます。 これは非常に単純なモンキーパッチになります。最初の引数を取り、これが必要なカスタム要素名と一致する場合(特定のリストか、すべて小文字で少なくとも1つのダッシュを含む文字列かどうか)、 ReactDOM.customElement()
呼び出します。その名前にReact.createElement()
転送します。
@ developit @ gaearonどちらかである可能性があります。 「マッピング」が必要な場合は、フックの方が持続可能だと思います。 ただし、Jasonが指摘したように、これはReactDOMのコアに実装される場合の正味の変更を示すことも目的としていました。
BCの場合、Reactで小文字のカスタム要素がどのように機能するかについては何も変更しないでください。 言い換えれば、JSXは
React 17でも16と同じように機能し続けます。または、マイナーなバグ修正が必要な場合は、別の問題を開いてそれらについて話し合ってください。
個人的には、 <x-foo>
要素をそのまま使用して、最初にラップすることなくプロパティを簡単に渡すことができるようにしたいと思います。
可能であれば、オプション1(クライアント側のプロパティ)と5(SSRの構成)の@sohpiebitsの提案を使用したいと思います。 多分人々が後方互換性ボーナスのためにオプション2(多分オプション2 + 5?)を再考することを私はまだ望んでいます。
@gaearon ReactDOMコアの一部である場合、Treyの提案に対するあなたの意見は変わりますか? もしそれが助けになるなら、たぶん私たちは例をもっと具体化することができますか?
オプション5に関する私の主な関心事は、相互運用性を可能にするために多くの定型文を作成し、DXを壊すことです。すべてのReactコアチームと貢献者が、望ましい影響を与えない変更に多くの時間を費やすことは残念です。
Reactチームが_PropTypes_のように、リポジトリの最後の変更をどのように処理したかが本当に気に入りました。複数のスイッチを含む計画を考えて、カスタムではなくカスタムに対して将来行う可能性のある変更について開発者を教育することをお勧めします。要素。
私たち全員を満足させる解決策は、_steps_、APIの追加、警告と非推奨、または動作の変更など、このオプションのいくつかを組み合わせたものになると思います。
たぶん、オプション5は警告付きで、後のオプション2は必要なラッパーの非推奨です。
たぶん、オプション5は警告付きで、後のオプション2は必要なラッパーの非推奨です。
私は実際、反対のことをすることがより良い一連のステップになるだろうと思っていました。 オプション1または2は、劇的な変化が少ないためです。 そして、それがどのように進行し、SSRストーリーがWebコンポーネントでどのように見え始めるかを測定します。 次に、オプション5をフォローアップします。これは、新しいAPIとプロキシ/ラッパーコンポーネントの概念が追加されるためです。
オプション1の主な問題は、それがかなり大きなBCブレークであるということです。 オプション2の主な問題は、要素のアップグレードがいつ完了するかによって競合状態が発生することです。 Reactと同じくらい広く使われているプロジェクトで、どちらも本当に受け入れられるかどうかはわかりません。
オプション5が利用可能であることを考えると、代わりに、オプション5以外の使用法をはるかに安全に、しかしそれでも有用に改善できるかどうか疑問に思います。 たとえば、オプション4の逆についてはどうでしょうか。 domProperties
とeventListeners
小道具を導入するだけで、次のようなことができます。
<x-foo
my-attr1={...}
domProperties={{myRichDataProperty: ...}}
eventListeners={{'a-custom-element-event': e => console.log('yo')}}
/>
domProperties
とeventListeners
は有効な属性名ではないため、これは完全な下位互換性があり
BCを保持することに加えて、このアプローチは理解しやすいです。これは属性中心(React小道具は要素属性として扱われることを意味します)であり、要素名自体がすべて小文字でダッシュがあり、したがってHTML中心である場合に適合します。 ただし、リッチデータを渡すなど、プロパティを渡す必要がある比較的まれなケースのために、 domProperties
が提供されています。
メンタルモデルをプロパティ中心(オプション1)に切り替えたい場合は、オプション5スタイルのAPIが役立ちます。
const XFoo = ReactDOM.customElement('x-foo');
<XFoo prop1={} prop2={} data-foo={} aria-label={} />
この構文では、すべての小道具がプロパティとして扱われます(オプション1)。 要素「name」(XFoo)もJS中心の規則に従っているため、これは当てはまります。 少なくとも、属性として扱われるdata-*
とaria-*
小道具をサポートしたいと思います。これらの小道具だけに制限するか、ダッシュ付きの小道具を一般化して、属性。
一方、SSRのオプション5構成をサポートするために、次のような構成APIをReactDOM.customElement
に追加できます。
const XFoo = ReactDOM.customElement('x-foo', ssrConfiguration);
おそらくssrConfiguration
は、 @ treshugartのコメントにあるReactDOM.setAttribute
似たコールバック関数である可能性がありますか?
どう思いますか?
@effulgentsia私はあなたの考えがどこにdomProps
/ domEvents
。 これはオプション4に非常に近いです。
WRT SSR、SSRは、コンポーネントが追跡していない場合にコンポーネントがそれ自体に変更する属性をReactが尊重できる限り、カスタム要素自体で処理できると思います。 以前に要点を投稿しましたが、便宜上、ここでも説明します: https :
@effulgentsia私もあなたが向かっているところが好きです。 @ sophiebits 、 @ gaearon do
みんなこの方向について考えていますか?
火、2017年10月31日には、7:33 PMのTrey Shugartの[email protected]は書きました:
@effulgentsiahttps ://github.com/effulgentsia私はあなたの場所が好きです
考えが進んでいます。 名前を少し自転車に乗せて、それは役に立つかもしれません
それらの名前を揃えます:domProps / domEventsなど。WRTオプション2は、少なくとも下位互換性があり、ほとんどのユースケースを解決します。
しかし、私は代替案に近づいています。SSRは、カスタム要素自体で処理できると思います。
Reactは、コンポーネントがそれ自体に変異する属性を尊重する可能性があります。
それらを追跡していません。 以前に要点を投稿しましたが、ここに再びあります。
快適:
https://gist.github.com/treshugart/6eff0da3c0bea886bb56589f743b78a6。
基本的に、コンポーネントはサーバー上でレンダリングした後に属性を適用します
そしてクライアントでそれらを水分補給します。 WebコンポーネントのSSRは可能ですが、
ソリューションはまだ標準レベルで議論されているので、
ここで提案のこの部分を待つのが最善です。—
あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/facebook/react/issues/11347#issuecomment-340960798 、
またはスレッドをミュートします
https://github.com/notifications/unsubscribe-auth/ABBFDeiQhBWNGXNplbVV1zluYxT-ntFvks5sx9hngaJpZM4QD3Zn
。
名前を少しバイクシェッド:domProps / domEvents。
私はそれらが好きです。 また、「dom」の概念を「ref」の概念に置き換えることで、Reactをさらに慣用的にする方法があるかどうかについてもブレインストーミングを行っています。 つまり、 refProps
/ refEvents
です。これは、小道具とイベントリスナーを「ref」にアタッチするためのものだからです。
そして、 this.props
内に新しい特別な名前を導入する代わりに、既存のref
JSX属性を単純にオーバーロードするとどうなるかを考えました。 現在、「ref」は、Reactコンポーネントがマウントおよびアンマウントされたときに呼び出される関数です。 それをオブジェクトとしても許可した場合はどうなりますか?
<x-foo my-attr-1={}
ref={{
props: ...
events: ...
mounted: ...
unmounted: ...
}}
/>
ただのアイデア。
私はこのアプローチが本当に好きです:)
これにフレンドリーなping。 @sophiebitsが行う@gaearon y'allのは@effulgentsiaの最新の提案上の任意の考えを持っていますか? それが球場にあるのか、それとも初心者ではないのか、興味があります。
RFCプロセスを開いたところです。 RFCとして提出するようにお願いできますか?
https://github.com/reactjs/rfcs
domProperties
とeventListeners
"props"(またはref = {{}}オブジェクト内の同等のもの)を追加したくないのは、カスタム要素の使用が非常に不自然になり、他のすべてのReactコンポーネントとは異なるためです。 コンポーネントユーザーがプロパティと属性の違いなどを鋭敏に知る必要がある場合は、ReactDOM.createCustomElementTypeスタイルのソリューションとしてそれを行います。 次に、コンポーネントを1回だけ使用する場合は、同等の作業量です(構成を指定してから、1回使用する)が、コンポーネントを何度も使用する場合は、毎回構成オブジェクトについて考える必要はありません。 毎回構成を指定する必要があると、何かが足りない場合を除いて、クリーンなカスタム要素の統合という目標を達成できないようです。
@sophiebits OK、そのようなもののRFCを作成しようと試みることができます。 10月26日にクライアント側で最初にプロパティを実行し、SSR用にReactDOM.createCustomElementTypeを記述できるようにする、および/またはクライアントがattrs / propertiesをマップする方法を非常にきめ細かく制御したい場合は、どう思いますか。 ?
少なくともcreateCustomElementType
スタイルでは、ライブラリはAPIをそれに簡単にマッピングできます。 つまり、skatejs / renderer-reactは、簡単にprops
を受け取り、Reactのカスタム要素を構成できます。 しかし、この種のバニラの人々は、抽象化や少しの作業を行うことなく、高くて乾燥したままになります。 きめ細かい制御を可能にしながら、安全なデフォルトのロブの提案が好きです。 それはうまくいくものですか?
@robdodson私はそれに乗っていると思います。 他に懸念が出ないことは約束できませんが、バランスが取れていると思います。
オプション3はこれまでのところ最良のオプションであり、SSRで機能する可能性があるため、その方法について説明します。
これまでのところ、3つを除くすべてのオプションはそれ自体です。
これが私たち全員が同意する普遍的なルールです:
setAttribute
を使用して属性を設定することは、宣言型HTML属性と1対1で一致する方法でデータを要素に渡すための、ユニバースで最も標準的な方法です。 これは、宇宙の法則として100%の時間機能する必要があるため、データを要素に渡す唯一の100%保証された方法です。したがって、最低限、Reactが_ユニバース内のすべての単一のカスタム要素で100%動作し、_ 、次のようになります。
setAttribute
を介してデータを渡すだけです。これは100%標準だからです。setAttribute
メソッドを拡張/オーバーライドして、 setAttribute
が文字列以外のものを受け入れるようにすることができるという事実を受け入れる必要があります。 代表的な例は、Aフレームのようなライブラリです。setAttribute
に依存して、デフォルトですべての要素と互換性を持たせる必要があります。すべてのライブラリは属性に依存しているため、ユニバース全体が相互に機能します。 _これについてifs、ands、またはbutsはありません!_ (w3c / whatwgがいくつかの大きな変更を加えない限り)Soooooooo 、そうは言っても、少なくとも
次に、オブジェクトプロパティAPIを持つ要素の影響について考えることができます。
setAttribute
を使用することを選択できます。したがって、属性とプロパティに関するこの知識を使用して、 たい_Reactのソリューションは
<x-foo blah="blah" />
が_デフォルトで_ setAttribute
マップされ、値を_unchanged_に沿って渡す必要があることを"[object Object]"
文字列が渡されることになります。オプション3は、シジル(追加の構文を学ぶのは正直難しいことではありません)を使用することで、理想に最も近いソリューションのようです。 このSOの質問に基づくと、使用可能な記号は=
のみですが、 &
(エスケープ可能な形式、おそらく\&
)のようなものに落ち着く方が読みやすくなります。 たとえば、特に小道具が必要な場合:
<x-foo &blah="blah" />
WHATWG HTML構文仕様でカバーされている他のほとんどの文字は機能するはずです。機能することを願っていますが、それは別のトピックです。
オプション3はこれまでのところ最良のオプションです。
クライアントでハイドレーションが使用されていないため、SSRで小道具が意味をなさない場合は、まあ。 以前は機能しなかったため、現在は機能する必要はありません。 PHPスタイルまたはJavaスタイルのSSRは、ハイドレーションなしで静的HTMLを送信し、属性に100%依存します。 つまり、React SSRを使用する場合は、おそらくクライアント側のハイドレーションを使用します。ハイドレーションが必要ない場合は、この場合は小道具を使用しないという事実に注意する必要があります。 _これは簡単です。 反応する必要があるのは、この警告をドキュメントで明確にすることだけです。_
しかし!!! それがすべてではありません! オプション5の機能を含めて、ユーザーがより細かく制御できるようにすることもできます。 オプション5のようなAPIを使用
結局、以下はうまくいく解決策のように思えます:
setAttribute
がデフォルトで舞台裏で使用され、明けましておめでとう!
上記の点のいくつかに答えたいと思いますが、このスレッドはすでに_信じられないほど_長いのではないかと心配しています。 だから、長くしてすみません:P
これが私たち全員が同意する普遍的なルールです:
setAttributeを使用して属性を設定することは、宣言型HTML属性と1対1で一致する方法でデータを要素に渡すための、ユニバースで最も標準的な方法です。 これは、宇宙の法則として100%の時間機能する必要があるため、データを要素に渡す唯一の100%保証された方法です。
これは完全に真実ではありません。 プラットフォームには、カスタム要素が属性インターフェイスを公開することを強制するものは何もありません。 JSプロパティのみを受け入れるものを同じように簡単に作成できます。 したがって、これは「データを渡すための保証された方法」ではありません。 強制メカニズムがないということは、どちらのスタイル(HTML属性またはJSプロパティ)にも100%確実に依存できないことを意味します。
文字列専用に設計されていることに不満を持っている人もいます。
一部の要素(繰り返しますが、一部の要素のみ)は、特定の属性にマップされるオブジェクトプロパティを介して値を受け入れます。 これは、100%の確率で信頼できるものではありません。
オブジェクト/配列などの豊富なデータを受け入れるプロパティの属性を作成することすらしないことをお勧めします。 これは、一部のデータをシリアル化して属性文字列に戻すことができないためです。 たとえば、オブジェクトプロパティの1つがDOMノードへの参照である場合、それを実際に文字列化することはできません。 また、オブジェクトを文字列化して再解析すると、そのIDは失われます。 つまり、別のPOJOへの参照がある場合、まったく新しいオブジェクトを作成したため、その参照を実際に使用することはできません。
文字列以外を受け入れることができるため、オブジェクトのプロパティが好きな人もいます
したがって、React shoudは、100%標準であるため、デフォルトではsetAttributeを介してデータを渡すだけです。
JavaScriptのプロパティも同様に標準です。 ほとんどのHTML要素は、属性と対応するプロパティインターフェイスの両方を公開します。 たとえば、 <img src="">
またはHTMLImageElement.srcです。
Reactは、カスタム要素の作成者がクラス定義のsetAttributeメソッドを拡張/オーバーライドして、setAttributeが文字列以外のものを受け入れるようにすることができるという事実を受け入れる必要があります。
作成者はそれを行うことができますが、実際には、JSプロパティを使用するよりもはるかに「非標準」のようです。 また、要素の解析と複製に関連する奇妙な問題にさらされる可能性があります。
Reactは、カスタム要素の作成者がカスタム要素をReactだけでなく、考えられるすべてのライブラリで機能させたい場合、その作成者はsetAttributeに依存して要素をデフォルトですべてと互換性のあるものにし、デフォルトですべてのライブラリが属性に依存することを受け入れる必要があります。 、その後、宇宙全体が互いに機能します。 これについては、ifs、ands、またはbutsはありません! (w3c / whatwgが大きな変更を加えない限り)
カスタム要素(Angularなど)にJSプロパティを設定することを好むライブラリが他にもあるため、この結論にどのように到達するかはわかりません。 最大限の互換性を得るには、作成者はJSプロパティを使用して属性をバックアップする必要があります。 それは可能な用途の最大の表面積をカバーします。 Polymerで作成されたすべての要素は、デフォルトでこれを行います。
デフォルトでは、属性が100%の時間機能することを許可します。 この意味は
デフォルトでは、setAttributeにマップし、値を変更せずに渡す必要があります。 これは重大な変更ではありません。 実際、これは修正の変更であり、そうでなければ意味のない「[objectObject]」文字列が渡されます。
Reactは実際には値を変更せずに渡すと思います。 setAttribute('foo', {some: object})
呼び出すと、 [object Object]
ます。 彼らがオブジェクトに対してJSON.stringify()
を呼び出すことを提案していない限り、 しかし、そのオブジェクトは「変更されていない」わけではありません。 setAttribute()
を上書きしたのは、作者に頼っているのではないでしょうか。 DOMにモンキーパッチを適用する代わりに、対応するJSプロパティを作成するように勧める方が妥当な場合があります。
Reactは実際には値を変更せずに渡すと思います。
setAttribute('foo', {some: object})
呼び出すと、[object Object]
Reactは、 setAttribute
に渡す前に、値を文字列に強制変換しています:
と
私はあなたが言ったことすべてに基本的に同意します。
私たちは、人々が両方の方法で物事を行っていることに同意します。また、すべての人にどちらか一方の方法でそれを強制する基準はないので、私はまだ考えています
setAttribute
使用され、インスタンスプロパティの使用を指定するための印章があります。オプション5が適切に実行されている場合、SSRソリューションのハイドレーションは、オプション5 APIを使用して指定できるように、データを属性または小道具のいずれかにマップできます。
Reactは、setAttributeに渡す前に値を文字列に強制変換します
分かりました。 ほとんどの人はカスタムtoString()
定義しないため、デフォルトで[object Object]
ます。
ほとんどの人はカスタム
toString()
定義しないため、デフォルトで[object Object]
ます。
私がするのと同じように
const div = document.createElement('div')
div.setAttribute('foo', {a:1, b:2, c:3})
結果は
<div foo="[object Object]"></div>
明らかに、Web開発者として、非文字列を要素属性に渡すとどうなるかを知っておく必要があります。 たとえば、文字列以外をA-Frame要素に渡すことができることを認識していますが、ライブラリが邪魔になることなく、自由にそれを行うことができます。
Reactは、それが神ではないことを認識する必要があります。React以外にも、人々が使用する他の多くのライブラリがあります。
これは不必要に卑劣です。 このスレッドでは、これについては気にしていますが、カスタム要素の設計をどこで行うかについては、さまざまなオプションとビジョンがあることに注意してください。 何をすべきかは確かに明らかではありません。
@sebmarkbage申し訳ありませんが、私はまったく卑劣であるでした。Reactは素晴らしいライブラリだと思います。 私はそこで私の言葉をもっと注意深く考えるべきでした(特に誰もが同じ宗教を持っているわけではないので)。
つまり、Reactは非常に人気があるため、Reactは、他の場所では機能しない可能性のある特定の方法で人々を動揺させる可能性があります(すべてのカスタム要素のインスタンスプロパティに依存するように人々に指示する可能性があります。 tすべてのカスタム要素で動作します)。
Reactは現在、要素属性に渡されたすべての値を文字列に変換します。 Reactがこれを行わなかった場合、たとえば、 aframe-react (文字列の問題を回避する)が存在する必要はありません。
プレーンJavaScriptの場合と同様に、Reactでデータを要素に渡す方法を選択できるようになれば、私は最も満足できるユーザーになります。 😊
繰り返しになりますが、そこでの私の言葉の選択について申し訳ありません。 次回は考え直します。
これについてRFCPRにコメントを追加しました。 提案されている内容と、カスタム要素とそのプロパティを確実に推測するためのより単純なモデルについて説明しているので、説明する価値があると思います。 それはハイブリッドアプローチに戻りますが、ほとんどのユースケースで統合するゼロ構成の方法を提供します。
この機能がReactに実装されるのを見たいと思っています。 Reactを素晴らしいものにするためのあなたの努力に感謝します。
このRFCの更新はありますか?
カスタム要素ライブラリは非常に良くなっているので、Reactアプリで使用したいと思います。 これに関するニュースはまだありますか? VueとAngularがコンポーネントをネイティブに簡単に処理していることを考えると、カスタム要素をラップし、それらのコンテンツを文字列化して後で再度解析することは、かなり実行不可能なソリューションです。
この問題に関する更新はありますか?
私も、ハックに頼らずにカスタム要素ライブラリを使用したいと思っています。 この問題が解決されることを望んでいます。
@ mgolub2 Reactチームは、Webコミュニティが何を望んでいるかを気にしません。 Webコンポーネントは現在広くサポートされている標準であり、2年後、この標準をサポートするためのチームからのシグナルはありません。
これにより、カスタム要素の作成者は次のようなことを行うことができます。
class MyElement extends HTMLElement {
setAttribute(name, value) {
// default to existing behavior with strings
if (typeof value === 'string')
return super.setAttribute(name, value)
// but now a custom element author can decide what to do with non-string values.
if (value instanceof SomeCoolObject) { /*...*/ }
}
}
拡張されたsetAttribute
メソッドがどのように見えるかには多くのバリエーションがありますが、これはほんの1つの小さな例です。
Reactチーム、カスタム要素の作成者は、場合によってはDOMのネイティブ属性処理をバイパスするため(値が文字列でない場合はfe)、そうすべきではないと主張するかもしれません。 あなたがその意見を持っているとしても、それでも、カスタム要素の作成者が__カスタム__要素で何ができるかを妨げる必要があるという意味ではありません。
Reactは、既存のDOMAPIがどのように使用されているかについて意見を述べるべきではありません。 ReactはDOMを操作するためのツールであり、データがDOMにどのように流れるかについてのみ、DOMに対して何ができるかについて意見を述べるべきではありません。 「データがDOMに流れる方法」とは、データを変更せずに、データがそこに到達するまでのルートを意味します(作成者のオブジェクトを文字列に変換すると、作成者のデータが変更されます)。
なぜ作者のデータを変更したいのですか? DOMを操作したい人が、どのデータをDOMに渡すかを知っていると仮定できないのはなぜですか?
@trusktrこれはhttps://github.com/facebook/react/issues/10070で議論されたと思い
setAttribute
ような組み込みメソッドをオーバーライドするようにカスタム要素の作成者に指示しないように人々に本当に警告します。 モンキーパッチを適用することを意図したものではないと思います。 cc @gaearon
そのようなサブクラスでsetAttribute
をオーバーライドすることは無害です(これはモンキーパッチではありません)。 しかし、私が述べたように、それが必ずしもReact libの仕事ではないのに、なぜReactがそれを指示しなければならないのですか? Reactを使用してDOMを操作したいと思います(支障なく)。
パフォーマンスを向上させるためにel.setAttribute()
手動で使用する必要がある場合、それは開発エクスペリエンスを悪化させるだけです。
Reactチームは、 setAttribute
に渡されたものを文字列に変換することで、多くの人々を大きな危険から救っているとは思いません。
私は別の解決策がより良いかもしれないことに同意します。 たとえば、JSX仕様を更新して新しい構文を追加しましたが、これには時間がかかるようです。
自動文字列変換を取り除いた場合、コミュニティは何を失いますか? Reactチームは何を失いますか?
Reactチームは、より良い解決策で、後で状況を改善することができます...
少なくとも、文字列化をバイパスするオプションを単に提供してみませんか? それはあなたが喜んで検討するかもしれない何かですか?
setAttribute
ような組み込みメソッドをオーバーライドするようにカスタム要素の作成者に指示しないように人々に本当に警告します。
その理由について、正当な理由を教えてください。
これは赤いニシンのようです。 「カスタム要素を作成するすべての人に、特定の動作をするメソッドを要素にアタッチするように説得する」は、DOM要素にプロパティを設定する方法に関するこの問題の解決策ではありません。
@trusktr
その理由について、正当な理由を教えてください。
Webコンポーネントは標準です。 したがって、標準の派生物も標準に準拠している必要があります。
ただし、 setAttribute
オーバーライドすることは、この条件に適合しません。Reactに対してのみハックを作成しますが、Webコンポーネントをそのまま使用できるフレームワークは他にもたくさんあります。 そのため、Reactをまったく使用しない場合でも、Reactハックを消費する必要があります。 私はそれが正しい解決策ではないと思います。
次に、標準メソッドにパッチを適用することは間違ったアプローチであることはよく知られています。 setAttribute
オーバーライドすると、元の動作が変更され、エンドユーザーが使用しようとしたときに混乱する可能性があります。 誰もが標準が標準として機能することを期待しており、カスタム要素はHTMLElement
動作を継承しているため、例外ではありません。 また、Reactで機能する可能性はありますが、他のすべてのユーザーにトラップを作成します。 たとえば、Webコンポーネントがフレームワークなしで使用される場合、 setAttribute
は頻繁に呼び出される可能性があります。 カスタム要素の開発者がこのアプローチで足を踏み入れることに同意するのではないかと思います。
個人的には、ある種のReactラッパーはもっと有望に見えると思います。
皆さん、待っている間に、Reacthttps : //www.npmjs.com/package/reactify-wcでWebコンポーネントをラップするためのシムを作成しました
import React from "react";
import reactifyWc from "reactify-wc";
// Import your web component. This one defines a tag called 'vaadin-button'
import "@vaadin/vaadin-button";
const onClick = () => console.log('hello world');
const VaadinButton = reactifyWc("vaadin-button");
export const MyReactComponent = () => (
<>
<h1>Hello world</h1>
<VaadinButton onClick={onClick}>
Click me!
</VaadinButton>
</>
)
これがお役に立てば幸いです
(これはOSSへの私の最初の進出であり、私のオフィスから何かをオープンソース化した最初の1つです。建設的な批判は大歓迎です😄)
皆さん、待っている間に、Reacthttps : //www.npmjs.com/package/reactify-wcでWebコンポーネントをラップするためのシムを作成しました
import React from "react"; import reactifyWc from "reactify-wc"; // Import your web component. This one defines a tag called 'vaadin-button' import "@vaadin/vaadin-button"; const onClick = () => console.log('hello world'); const VaadinButton = reactifyWc("vaadin-button"); export const MyReactComponent = () => ( <> <h1>Hello world</h1> <VaadinButton onClick={onClick}> Click me! </VaadinButton> </> )
これがお役に立てば幸いです
(これはOSSへの私の最初の進出であり、私のオフィスから何かをオープンソース化した最初の1つです。建設的な批判は大歓迎です😄)
素晴らしいラッパー:)
Stencilを使用してWebコンポーネントを構築すると、Reactでこの問題が修正されることにも言及する価値があります:
@matsgmステンシルを使用した構築が
このスレッドを最新の状態にしようとしているだけです。 最終的な解決策は何ですか?
ある意味で、私は非常に混乱する可能性のある魔法のヒューリスティックではなく、attr、prop、eventを明示的に定義することの大ファンです。
たとえば、 snabbdomは明示的なトップレベルの名前空間を使用します。これにより、何がどこに行くのかを簡単に知ることができます。 実行が高速な文字列操作はありません。たとえば、 onClick
=> click
からのサフィックスのトリミングは依然としてパフォーマンスヒットです。
<input attrs={{placeholder: `heyo`}} style={{color: `inherit`}} class={{hello: true, world: false}} on={{click: this.handleClick}} props={{value: `blah`}} />
attr = (attr, val) => elem.setAttribute(attr, val);
prop = (prop, val) => elem[prop] = val;
on = (event, handler) => elem.addEventListener(event, handler)
style = (prop, val) => elem.style[prop] = val;
class = (name, isSet) => isSet ? elem.classList.add(name) : elem.classList.remove(val)
dataset = (key, val) => elem.dataset[key] = val;
JSXがドット構文を使用した名前空間をサポートしていることを望みます。 これは、小道具がデフォルトの名前空間になり、簡単に書くことができることを意味します
<div tabIndex={-1} attr.title={"abcd"} on.click={handler} style.opacity={1} class.world={true} />`
fyi @sebmarkbage ^
const whatever = 'Whatever';
const obj = { a: 1, b: 2 };
const reactComponent = (props) => (
<div>
...
<custom-element attr="{whatever}" someProp={obj} />
{ /* double quotes for attributes */ }
{ /* no quotes for properties */ }
</div>
);
これは、React JSXPragmaパーサーを変更することで実現できます。
追加のオプションは、プロパティを渡すための指定された単語としてpropeties
(または反応ファンの場合はprops
)を保持することです
17.0が本日リリースされたので、この問題がいつ対処されるかというステータスを反映するようにこの問題を更新できますか?
うん。 当初、React 17は、より多くの非推奨が削除された(そして新しい機能を備えた)リリースになる予定でした。 ただし、古いコードベースがすべてのコードを更新することはあまり現実的ではありません。そのため、1つの重要な重大な変更のみに焦点を当てたReact 17をリリースすることにしました(イベントはドキュメントではなくルート要素に添付されます)。 )。 これは、古いアプリがReact 17に永久に残り、それらの一部のみを18+に更新できるようにするためです。
この特定の機能が17に入ると言っていたのはイライラすることですが、当初17で計画していたもののほとんどすべてが18に移動されたことに気付くでしょう。 17は特別な踏み石リリースです。 これにより、18でより積極的な破壊的な変更を加えることができます。明確な道筋がある場合は、これを含める可能性があります。
これらのオプションのどれが好ましいかについて、WCコミュニティからの最新のコンセンサスが何であるかはわかりません。 ただし、それらすべてを書き留めておくと非常に役立ちます(その作業を行うための@robdodsonへの大きな小道具)。 このスレッドが書かれてから、これらのオプションに関する人々の意見が進化したかどうか、そして私たちが方向性を選ぶのに役立つ新しい情報があるかどうか、私は興味があります。
WCコミュニティが優先オプションを変更したとは思いません。これはまだオプション3です。 Reactにとっても興味深いかもしれません。 フレームワークが(複雑な)データをカスタム要素に渡すこととどのように互換性があるかについての一般的な概要については、 https://custom-elements-everywhere.com/にすべての詳細があります。
https://github.com/vuejs/vue/issues/7582で、Vueは印章を使用することを選択し、「。」を選択したことに注意して
https://github.com/vuejs/vue/issues/7582#issuecomment -362943450で、 @ trusktrは、最も正しいSSR実装は、SSRされたHTMLの属性としてsigilされたプロパティをレンダリングしないことであると提案しました。代わりに、水和中にJSを介してプロパティとして設定します。
この特定の機能だけのために新しいJSX構文を導入する可能性はかなり低いと思います。
オプション(5)のより一般的なバージョンがテーブルにある可能性がある場合、オプション(3)を実行する価値があるかどうかという問題もあります。 つまり、オプション(5)は、カスタムのマウント/更新/アンマウント/ハイドレーション動作でカスタムの低レベルのReactノードを宣言するための低レベルのメカニズムである可能性があります。 カスタム要素自体に固有ではありません(ただし、それらはユースケースの1つです)。
この特定の機能にまったく新しいJSX構文を導入するのではなく、より一般的なJSXを導入し、それを使用してカスタムプロパティを定義するのはどうでしょうか。
私はずっと前にECMAScriptの計算されたプロパティ構文をJSXに追加することを提案しました(facebook / jsx#108)、そしてそれは一般的な構文への有用な追加になると思います。
計算されたプロパティ構文が利用可能である場合、計算されたプロパティ構文とシンボルまたはプレフィックス付き文字列を使用してプロパティを定義する可能性が残ります。
例えば:
import {property} from 'react';
// ...
<custom-img [property('src')]="corgi.jpg" [property('hiResSrc')]="[email protected]" width="100%">
@dantmanこの提案は、サーバーのレンダリングとハイドレーションをどのように処理しますか?
WCコミュニティの誰もがオプション5を望んでいるとは思いません。
これは、カスタム要素のカスタムReactラッパーを作成するパッチを適用する現在の慣行とまったく同じです。 このアプローチの大きな欠点は、コンポーネントの作成者が特殊なケースのReactを使用するか、コンポーネントのコンシューマーが特殊なケースのカスタム要素を使用するかのどちらにも負担がかかることです。どちらも必要ありません。
サーバーのレンダリングとハイドレーションについてどう思いますか? 明示的な構成がない場合、どのヒューリスティックが望ましいですか? これがWCコミュニティで通常行われる方法に統合がありましたか? 私はこのRFCを読み直しましたが、このトピックの詳細については詳しく説明していないようです。 しかし、特にReactがサーバーのレンダリングをより重視する方向に進んでいるため、これは非常に重要です(クライアント中心のデフォルトが多すぎると正当に批判されることがよくあります)。
@gaearon何が必要かを知るのに十分なハイドレーションとカスタムプロパティがわかりません。これは、主に構文の提案です。
一般的な考え方は、 property(propertyName)
は、実装方法に応じて、プレフィックス付きの文字列( '__REACT_INTERNAL_PROP__$' + propertyName
)を出力するか、シンボルを作成して「symbol => propertyName」の関連付けをに保存することができます。地図。
そのマップをクライアントに伝達する必要がある場合、後者は問題になる可能性があります。
ただし、大まかに理解すると、プロパティはサーバーで処理できるものではなく、ハイドレーションにはクライアントコードが含まれるため、その計画が何であるかはわかりません。 私の提案に関しては、それはおそらくあなたがその問題を解決しなければならないどんな計画にも適応することができます。 サーバー上のプロパティに対して反応させる予定の何かがある場合、 property
によって作成されたプロパティの1つを見ると、それを実行できます。
Webコンポーネントライブラリの作成者として、オプション5は便利な選択ではありません。 フレームワークやコンポーネントごとにスキーマを明示的に定義せずに、カスタム要素を作成したいと思います。 そして、多くのカスタム要素の作成者はこれを行わないため、React開発者の負担が大きくなります。
オプション5では誰も勝ちません。😕
@claviskaサーバーのレンダリングとハイドレーションがより暗黙的なアプローチでどのように機能するかについて意見はありますか?
@gaearon SSRは、カスタム要素がSSRをサポートする状況とサポートしない状況の2つの状況に細分されます。
SSRをサポートしない要素の場合、サーバーでのプロパティの設定は重要ではありません。 id
やclassName
ような組み込みのリフレクティングプロパティを除いて、それらはドロップしてクライアントにのみ書き込むことができます。
SSRプロパティをサポートする要素の場合は重要ですが、それは、DOMで発生する結果をトリガーできるようにするためだけです。 これには、要素インスタンスまたはある種のSSRプロキシ/スタンドイン、およびSSRのDOM状態を通信するためのプロトコルが必要です。 このプロセスに共通のサーバー側インターフェースはまだないので、今のところここで行うことは実際には何もありません。 Webコンポーネントの作成者とライブラリのメンテナは、Reactがそこにブリッジを構築することが実行可能になる前に、いくつかのことを理解する必要があります。
SSRに私のチームの仕事では、我々は、パッチを適用して反応を統合しているcreateElement
して使用してdangerouslySetInnerHTML
。 それが私たちが少しの間行う統合/実験のレベルだと思います。 近いうちに、SSRシステム内の相互運用のためにいくつかのユーザーランドプロトコルに収束できることを願っています。 それまでは、_deep_SSRなしでカスタム要素のプロパティとイベントをサポートすることは完全に安全で賢明です。 要素のタグは、現在のようにReactコンポーネントの子としてSSRされます。
idやclassNameなどの組み込みのリフレクティングプロパティを除いて、それらは削除してクライアントにのみ書き込むことができます。
これがどのように機能するかを理解するのを手伝ってもらえますか? たとえば、 <github-icon iconname="smiley" />
ます。 SSRがHTML応答に<github-icon />
を含めるだけで、Reactがハイドレーション中にdomNode.iconname = ...
を設定するということですか? その場合、Reactのハイドレーションが発生する前に、カスタム要素の実装が読み込まれるとどうなるかわかりません。 iconname
がHTMLに存在しない場合、 github-icon
実装はどのアイコンをレンダリングするかをどのように知るのでしょうか?
このプロセスに共通のサーバー側インターフェースはまだないので、今のところここで行うことは実際には何もありません。 Webコンポーネントの作成者とライブラリのメンテナは、Reactがそこにブリッジを構築することが実行可能になる前に、いくつかのことを理解する必要があります。
コミュニティがここでコンセンサスを形成するために特に起こるべきことがあるかどうか私は興味があります。 Reactはそれを抑制しているのですか? この問題が2017年から開かれていることに伴う不満をよく理解しています。一方、3年が経過しており、このコンセンサスはまだ形成されていないとおっしゃっていると思います。 それが起こるための前提条件は何ですか? それはもっと実験の問題ですか?
@gaearon Reactハイドレーションが発生する前にカスタム要素の実装が読み込まれると、 iconname
属性のdafault値が何であれ割り当てられます。 if _iconname_ does not exist in the HTML
とはどういう意味ですか? HTMLElementタイプに属性が定義されていない場合、それは無視されます。 カスタム要素定義が読み込まれると、HTMLElementタイプが拡張され、 iconname
定義され、渡された新しい値に反応できるようになります。
私はこれをユーザーの視点から理解しようとしています。 サーバー上でページをレンダリングしています。 テキストの中央にアイコンがあります。 そのアイコンはカスタム要素として実装されています。 エンドユーザーが経験すべき一連のことは何ですか?
これまでの私の理解は次のとおりです。
彼らは最初のレンダリング結果を見る。 通常のマークアップはすべて含まれますが、 <github-icon>
カスタム要素はまったく表示されません。 おそらくそれは空のdivのような穴でしょう。 私が間違っている場合は私を訂正してください(?)。 その実装はまだロードされていません。
<github-icon>
カスタム要素の実装が読み込まれ、登録されます。 私が正しく理解していれば、これは「アップグレード」と呼ばれるプロセスです。 ただし、JSの準備ができていても、HTMLにiconname
が含まれていないため、何も表示されません。 そのため、どのアイコンをレンダリングするかについての情報がありません。 これは、「組み込みでないプロパティはHTMLから削除できる」と前述したためです。 したがって、ユーザーにはまだ「穴」が表示されます。
Reactとアプリケーションコードが読み込まれます。 水分補給が起こります。 水分補給中に、Reactはヒューリスティックに従って.iconname =
プロパティを設定します。 これで、ユーザーにアイコンが表示されます。
これは、カスタム要素JS実装が最初にロードされる場合の正しい内訳ですか? これはWCコミュニティにとって望ましい行動ですか?
@gaearonうん、それは私がこの状況で起こると私が期待することです。
一方で、3年が経ちましたが、このコンセンサスはまだ形成されていないとおっしゃっていると思います。
コンセンサスが得られていないと言っているのではありません。 今のところ_deep_SSRについて心配する必要はなく、今すぐ達成できて非常に役立つ最も基本的なクライアント側の相互運用性を、かなり漠然とした懸念が妨げてはいけません。
私はこれまでこの区別を見たことがないので(深い対浅い)、私があなたを理解したかどうかを確認するためにそれを言い換えてみましょう。
「深い」SSRとは、Reactコンポーネントでの動作と同様のSSRを意味すると思います。 つまり、CEをレンダリングすると、そのCEのロジックがロードされる前に表示できる出力が生成されます。 これは、今サポートすることを心配する必要はないとあなたが言っていることです。 それは私には理にかなっています。
「深くない」SSRとは、CEタグ自体をHTMLに挿入しただけだということだと思います。 それが何に解決されるかを心配することなく。 それは私にも理にかなっています。 私の質問は、「この」フローについてでしたが、「深い」SSRについてではありませんでした。
特に、 https: //github.com/facebook/react/issues/11347#issuecomment -713230572は、CEロジックをダウンロードした場合でも、水分補給するまでユーザーに何も表示できない状況について説明しています。 アプリケーション全体のJSクライアントコードがロードされてハイドレーションが発生するまで、そのプロパティは不明になります。 これが本当に望ましい動作であるかどうかを尋ねています。
私の観点からは、漠然とした懸念ではないと思います。 機能リクエストを誤解したくありません。 したがって、指定された正確なセマンティクスを取得すると、この提案を評価するのに役立ちます。 たとえば、実際的な懸念の1つは、組み込みコンポーネントのいずれもそれを必要としないため、Reactが今日の水和中に本番環境で属性/プロパティを実際に比較しないことです。 しかし、それが本当に必要な場合は、この特定のケースに追加できるものです。
@gaearon
https://github.com/facebook/react/issues/11347#issuecomment -713230572は、この機能が必要な最良の例ではないかもしれません。
少なくとも私の経験では、属性ではなくプロパティを設定することは、文字列、数値、ブール値などの単純な型に必要なすべてではありません。
あなたが説明するケースは、属性としてiconname
を直接使用するだけで簡単に達成でき、水分補給を待たずに、ほぼ同じ最終レンダリング結果になります。
NS
カスタム要素の実装が読み込まれ、登録されます。 私が正しく理解していれば、これは「アップグレード」と呼ばれるプロセスです。 ただし、JSの準備ができていても、HTMLにアイコン名が含まれていないため、何も表示されません。 そのため、どのアイコンをレンダリングするかについての情報がありません。 これは、「組み込みでないプロパティはHTMLから削除できる」と前述したためです。 したがって、ユーザーにはまだ「穴」が表示されます。
ここで言及することに関しては、コンポーネントがどのように実装されているかに応じて、「穴」が表示されるというこの問題を回避できます。
これは、この場合は単純にデフォルトを設定するか、スロットを介してコンテンツの一部または大部分を受け入れ、コンポーネントがアップグレードされる前でもコンテンツが表示されるようにすることで実現できます。
この機能は、オブジェクト、配列、関数などのプロパティを持つ、より複雑なコンポーネントを使用する場合に最も役立つと思います。
例として、 lit-virtualizer
仮想スクローラーコンポーネントを取り上げます。
これが正しく機能するためには、 items
配列とrenderItem
関数が必要であり、オプションでscrollTarget
要素を設定することもできます。これらはすべて、
このような場合は、何らかのページ付けまたは遅延読み込みを使用してコンテンツを読み込む可能性があるため、SSRケースのハイドレーションステップまでコンテンツがないことはそれほど問題にはならない可能性があります。
@gaearonカスタム要素はDOM標準であるため、カスタム要素を使用するすべての人が同じように使用するという意味で、それ自体が「WCコミュニティ」ではないことに注意してください。 カスタム要素は、本質的に人々が構築する低レベルのプリミティブであるため、開発者ごとに独自の方法で統合されます。
とは言うものの、時間の経過とともに多くのパターンが出現し、すべての一般的なフレームワーク(Reactを除く)は、このDOM標準との互換性を提供するためのソリューションを実装しています。 https://custom-elements-everywhere.com/で確認できるように、すべてのフレームワーク/ライブラリ(Reactを除く)は異なるオプションを選択しています。 この号では、選択したオプションがオプション1、2、3としてリストされています。現在オプション4または5を実装しているフレームワーク/ライブラリはなく、これらを実装することは望ましくないと思います。
したがって、Reactは他のフレームワーク/ライブラリに準拠し、オプション1〜3など、機能することが証明されているオプションを選択することを提案します。 データがないオプション4または5を選択して、Reactがここで車輪の再発明を行う必要はないと思います。これは、ReactまたはDOM標準に基づいて構築されたソリューションの長期的な保守可能なソリューションです。
したがって、削除のプロセス(以下にリンクされているコメント付き)によって、オプション3はJSXに対して実行されず、オプション4と5は、このスレッドのWC担当者によって望ましくないとマークされているため、1または2でスタックします。 。
そして、1には受け入れがたい欠点があるように思われるので、オプション2が1つであるように見えますか? Preactのやり方に合わせてください。
現在、オプション4または5を実装しているフレームワーク/ライブラリはなく、これらを実装することは望ましくないと思います。
(https://github.com/facebook/react/issues/11347#issuecomment-713474037の@TimvdLippe )
この特定の機能だけのために新しいJSX構文を導入する可能性はかなり低いと思います。
(https://github.com/facebook/react/issues/11347#issuecomment-713210204の@gaearon )
はい、それは私には理にかなっています。 まとめてくれてありがとう! 😄
少なくとも私の経験では、属性ではなくプロパティを設定することは、文字列、数値、ブール値などの単純な型に必要なすべてではありません。 あなたが説明するケースは、iconnameを属性として直接使用するだけで簡単に実現でき、水分補給を待たずに、ほぼ同じ最終レンダリング結果になります。
私は完全にはフォローしていません。 私の仮定のシナリオでは、に応じたhttps://github.com/facebook/react/issues/11347#issuecomment我々はEMITのを除いて、すべてのサーバが生成したHTMLの属性はならないことを示唆のように聞こえた-713223628
<github-icon iconname="smiley" />
<github-icon icon={{ name: "smiley" }} />
ありがとう!
React.createElement()
をカスタム実装に置き換えて、シムを作成するオプションと見なされましたか?これは、プロパティが内部でマッピングされますか?
使用例:
/** <strong i="8">@jsx</strong> h */
import { h } from 'react-wc-jsx-shim';
function Demo({ items }) {
return <my-custom-list items={items} />
}
ドラフト実装:
export function h(element, props, children) {
if(typeof element === 'string' && element.includes('-')) {
return React.createElement(Wrapper, { props, customElementName: element }, children)
}
return React.createElement(element, props, children);
}
function Wrapper({customElementName, props}) {
const ref = React.useRef();
React.useEffect(() => {
for(const prop in props) {
ref.current[prop] = props[prop];
}
});
return React.createElement(customElementName, { ref, ...props });
}
これは組み込みの機能ではないことは知っていますが、オーバーヘッドが非常に少ないユーザーのブロックを解除する必要があると思います。
@ just-borisは、基本的にアプリまたはライブラリが現在行っていることであり、 createElement
パッチまたはラッパーのいずれかを使用します。 また、Reactで特殊なケースのプロパティ名を除外する必要があります。 エクスポートされたリストはないと思うので、 ['children', 'localName', 'ref', 'elementRef', 'style', 'className']
ような拒否リストをハードコーディングするだけです。
参照ベースであるため、プロパティはサーバーに設定されません。 これが私が懸念を曖昧と呼ぶ理由です。 Reactでプロパティを設定する方法はまったくないので、今はすべて壊れています。 利用可能な回避策は、すでにクライアントでのみ機能します。 サーバーではなくクライアントにプロパティを設定する組み込みの方法が組み込まれた場合でも、SSRが突然修正または中断されることはありません。
私は実際にはSSRよりもイベントに関心があります。 Reactにはイベントハンドラーを追加する方法がありません。これは、基本的なDOMAPIとの相互運用性における大きな穴です。
React.createElement()をカスタム実装に置き換えて、シムを作成するオプションと見なされましたか?これは、プロパティが内部でマッピングされますか?
元の号でRobが述べたように、私は過去にhttps://github.com/skatejs/valを介してこれを実験したことがあるので、 React.createElement
をラップするカスタムJSXプラグマを持つことは実行可能です-おそらく短期-解決策。
また、SkateのWIPブランチには、特にReact用にディープSSRとシャローSSRの両方を実装しています。 これまでのこの作業から学んだことは、各ライブラリが独自のAPIとアルゴリズムに依存しているため、ディープSSRを実行する場合、すべてのライブラリに単一のJSXラッパーを設定することはできないということです。 (コンテキストとして、Skateには、ライブラリのコアカスタム要素部分と、市場で人気のある各ライブラリを統合して消費と使用を全面的に一貫させるために構築された小さなレイヤーがあります。)
私はもうオープンソースであまり活動しておらず、Twitterももう行っていないので、一粒の塩で自由に意見を聞いてください。
オプション1は、オプション2の悪魔の擁護者として存在しているように感じます。
オプション2は進むべき道のように感じます。 これはPreactが行ったことに近いので、コミュニティ標準の前例と可能性があり(とにかく行うのは素晴らしいと思います。JSXはこれが機能することを示しています)、アップグレードが簡単であるという点でReactの実用的な動きでもあります。 (オプション1とは対照的に)。
オプション3は紙の上では見栄えがしますが、認知的オーバーヘッド、前述のオーバーヘッドに関する文書化、およびSSRでの未知数のために、ロジスティック的にはオプション2よりもはるかに難しいと思います。
前述のように、私は最初にオプション4を提示しましたが、熟考した後、それがもう好きかどうかはわかりません。 明示的なprops
とevents
( attrs
代わりに)を指定するオプトインに変更することもできますが、それでもオプション2では実装の詳細に関する知識が少なくて済みます。そしてそれを採用するために誰もが変更しなければならないことは何もありません。
オプション5は、コアの問題を完全に無視しているように感じます。
余談ですが、これが牽引力になっているのを見てとてもうれしく思います。皆さんが順調に進んでいることを願っています。
ユーザーランドで可能な解決策がある場合、それを統合して、当面の間コミュニティによって推奨できますか?
人気があり実行可能なサードパーティモジュールとしてすでに存在する場合、Reactコアチームに機能を追加するよう説得する方がはるかに簡単です。
vuejs / vue#7582では、Vueが印章を使用することを選択し、「。」を選択したことに注意してください。 プレフィックスとして(グリマーの「@」ではありません)。
これに関する信頼できる声明へのリンクはありませんが(おそらくVueに近い人が明示的に確認できます)、VueはVue 3.0の時点でオプション2に移行したようです。つまり、Preactと同様に動作します。 (コンテキストについては、この問題を参照してください。)
参照ベースであるため、プロパティはサーバーに設定されません。 これが私が懸念を曖昧と呼ぶ理由です。 Reactでプロパティを設定する方法はまったくないので、今はすべて壊れています。 利用可能な回避策は、すでにクライアントでのみ機能します。 サーバーではなくクライアントにプロパティを設定する組み込みの方法が組み込まれた場合でも、SSRが突然修正または中断されることはありません。
https://github.com/facebook/react/issues/11347#issuecomment-713514984の特定の質問に回答して
ここで偶然見つけたPreact + WC開発者として、「オプション2」は_重大な変更_であるだけでなく、_不完全な解決策_でもあることを指摘したいと思います(Preactはまだ有効なWebコンポーネントのサブセットと宣言的にのみ対話できます)。
ヒューリスティックの現在のユーザーとしてさえ、それは長期的にはほとんど望ましくないように聞こえます。
Preactのヒューリスティック(「オプション2」)は、React(キー、子など)またはPreact( on
始まるもの)で特別な意味を持つプロパティを設定できません。
つまり、JSXの下でレンダリングした後:
<web-component key={'key'} ongoing={true} children={[1, 2]} />
プロパティkey
、 ongoing
、およびchildren
は、作成されたweb-component
インスタンスですべてundefined
(またはデフォルト値)になります。
また、OPとは異なり、このオプションも重大な変更です。 ほとんどのWebコンポーネント(たとえば、 lit-element
)は、純粋なHTMLで使用するために、属性を介してシリアル化されたリッチデータを渡す機能を提供します。 そのようなコンポーネントは、Reactからそのようにレンダリングできます
<web-component richdata={JSON.stringify(something)} />
「オプション2」を選択すると壊れます。 ReactでこのようなWebコンポーネントの使用がどれほど一般的であるかはわかりませんが、そうするコードベースは確かにいくつかあります。refsよりも効率が低く、簡潔です。
最後に、Web Componentの作成者は、同じ名前の属性とプロパティに微妙に異なるセマンティクスを自由に付けることができます。 例としては、ネイティブのinput
要素の動作を模倣するWebコンポーネントがあります。属性value
を初期値として扱い、プロパティvalue
変更のみを監視します。 このようなコンポーネントは、ヒューリスティックなアプローチでjsxを介して完全に相互作用することはできず、導入された場合は微妙な破損が発生する可能性もあります。
この特定の機能だけのために新しいJSX構文を導入する可能性はかなり低いと思います。
名前空間の使用はどうですか? https://github.com/facebook/jsx/issues/66は、 key
とref
react
名前空間を追加することを提案しています。 同じように、 react-dom
ようなものは、DOMプロパティを識別するために作成するのに適した名前空間でしょうか? OPのオプション3の例を使用すると、次のようになります。
<custom-img react-dom:src="corgi.jpg" react-dom:hiResSrc="[email protected]" width="100%">
それは最も人間工学的ではありません。 dom
だけの方が良いでしょうが、Reactがreact
始まらない名前空間をミントしたいかどうかはわかりません。 また、プロパティとして設定することはあまり一般的ではないはずであるという考えであれば、これに関する人間工学の悪さは世界の終わりではありません。 属性を使用すると、SSRと同等になるため、より適切です。 プロパティとして設定するのは、属性に問題がある場合(オブジェクトを渡す場合や、属性に裏付けられていないプロパティの場合など)であり、問題のあるプロパティの場合は、とにかく属性にSSRできず、ハイドレイトする必要があります。 JS経由。
_不完全な解決策_
(Preactは、有効なWebコンポーネントのサブセットと宣言的にのみ対話できます)
@brainlessbadger上記のコメントを編集して、このサブセットが実際に何であるかを含めることもできますか? 例えば。 どのWebコンポーネント/カスタム要素が影響を受けますか(例を含む)? そして、それらはどの程度正確に影響を受けますか?
@karlhorky説明を追加しました。 不必要に曖昧になってすみません。
Webコンポーネントイベントについて。 イベントの名前を衝突させることによって将来のブロックを回避する方法について、まだコンセンサスはありますか?
これらすべてのように新しい属性をHTMLElementに追加できるため、これは属性とプロパティの問題でもあります。https ://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes新しく追加されたものもあるので、まだ新しいものが追加されています。
厳密に言えば、カスタム属性またはカスタムイベントの名前には-
を使用する必要があると思います。
それ以外のものは、そのコンポーネントが将来の仕様で適切な名前を使用できないようにするリスクを比較検討する妥協案です。
ただし、イベントは、そのコンポーネントが互換性のない動作をするリスクだけではないため、私をさらに緊張させます。 新しいイベントがバブルすると、そのツリーパス内の既存のすべてのWebコンポーネントがトリガーされます。
カスタム属性とイベントが名前に-
を使用する必要がある場合、これ
プロパティは、より良い速記を提供するための便利さとして使用できます。 少なくともそれらは組み込みプロパティをシャドウし、将来のプロパティと衝突することはありません。
厳密に言えば、カスタム属性またはカスタムイベントの名前に-を使用する必要があると思います。
カスタム要素の仕様にはそのような制限が含まれていないため、Reactでそれらを適用すると、相互運用性に大きな影響を与えます。
カスタム要素の作成者は、フレームワークの任意の要件に同意することを期待されるべきではありません。 さまざまな意見や慣習でこれを行うすべてのフレームワークを想像してみてください。 これは、Webコンポーネントを使用する目的を無効にします。 😕
理想的には、フレームワークは標準に対応するように適応する必要があります。
それはそう。 setAttribute()
とdispatchEvent()
は、Webコンポーネント固有ではないAPIであり、開始以来任意の名前を許可しています。 任意の要素が任意の属性を持ち、任意のイベントを発生させることができます。これはDOMの単なるグラウンドトゥルースです。
ただし、 data-
名前空間が追加されたのには理由があります。 技術的にできることとベストプラクティスには違いがあります。 技術的にはプロトタイプにパッチを適用することもできますが、そうすると、contains / includesシチュエーションが発生します。
Reactだけがこれを追加することを提案するのではなく、コミュニティが将来の名前空間を保護するためにこの規則に移行することを提案します。 この問題が真剣に受け止められていないのは残念だと思います。 しかし、おそらくWebは、新しいAPIに厄介な名前を追加するだけの運命にあります。
SSRから非ビルトインを除外するというアイデアが好きで、宣言型のシャドウDOMを使用すると、実際のコンテンツを内部で拡張できるため、ハイドレーション中にプロパティを優先します。
具体的には、属性を使用し、AMPランタイムがすでにロードされていると想定できるため、SSR + AMPで使用されている現在のアプローチに問題が発生すると思います。
オプション3でドアが閉じられていないと仮定すると、上記の短所にリストされていないオプション2よりも大きな利点があります-オプション2で私が見つけた問題は、Webコンポーネントライブラリが非同期で読み込まれる場合、preactがそうではない可能性があることです未知の要素については、「プロパティ」がプロパティになることを知っています。 不明な要素に存在するプロパティが見つからないため、デフォルトで属性になります。 回避策は、依存するWebコンポーネントライブラリが読み込まれるまで、そのコンポーネントをレンダリングしないことです。これは、あまりエレガントではありません(またはパフォーマンス面で理想的ではありません)。 私のグループはnode.jsではなくasp.netを使用しているため、SSRを実際に調べたことがないため、以下の観察結果は推測に基づくものです。
Reactチームの側では、SSRに関しては、他のフレームワークがサポートするものを超えて(私の知る限り)、オブジェクトのプロパティを最初のレンダリング中に渡すことができるようにすることを提案するのは良いジェスチャーだと思います。ユーザーの方が良い。
明白なことを言っているかどうかはわかりませんが、一部のプロパティでは、JSON文字列を介して属性の初期値を設定すると便利なWebコンポーネントとのコンセンサスが少しあると思います。一重引用符で囲まれています。
ただし、AMPは別の規則を使用します。これを行うには、 script type = application.jsonを
しかし、属性アプローチに固執する:
次に、Webコンポーネントライブラリは属性を解析するか、プロパティを介して値を渡すことができます。
したがって、水分補給の遅れを避けるために、以下を設定すると便利です。
<github-icon icon='{"name":"smiley"}'></github-icon>
SSR中。 そうすれば、github-iconはすぐにその処理を実行し、内部で属性のJSON.parseを実行し、Reactが(より完全な?)オブジェクト値を渡すのを待つ必要がなくなります。
したがって、今はトリッキーな状況になっています。サーバーでレンダリングする場合、「アイコン」を属性として扱い、値をオブジェクトとして渡すことができます。理想的には、SSRメカニズムが属性に文字列化されます。 クライアントでは、オブジェクトを直接渡すことができ、文字列化と解析のオーバーヘッドを通過しないようにする必要があります。
もちろん、一部のプロパティは文字列化/解析に適さないオブジェクトであるため、これは適用されません。これらのプロパティは、ハイドレーションが完了するまで待機する必要があります。
すべてのプロパティと属性がReactチームの推奨命名規則に従っている場合(おそらく)-すべての属性にダッシュがあり、すべてのプロパティがキャメルケースを使用した複合名である場合、ダッシュの存在は属性とプロパティを区別するのに役立つ可能性があります:
<github-icon my-icon={myStringifiedProperty} myIcon={myObjectProperty}></github-icon>
上記の構文では問題は何もありません。サーバーとクライアントで何をするかを示しています。理想的には、両方に1つのバインディングを使用でき、Reactはどちらを使用するかを判断するのに十分賢いでしょう。
Reactは、属性/プロパティキーがキャメルケースの場合、常にクライアント側のオブジェクトとして渡し、SSR中に設定されている場合はオブジェクトのJSON文字列化されたシリアル化を想定することができます。 同様に、キーのダッシュは(安全に、私は思うに)それが属性であると想定し、値の.toString()を渡すだけです。 しかし、これはあまりにも多くのことを想定していると思います。 また、HTMLElementを拡張するWebコンポーネントに属性が適用されている場合に有効なHTMLと見なされる単一の単語の属性とプロパティをサポートしないと、制限が厳しすぎます。 私は、W3Cが将来使用する可能性のある「予約済み」属性名のリストを発行することに賛成です。これはJSの予約済みキーワードと同様であり、フレームワークは、開発者が予約済み属性名を不適切に使用している場合に警告する方法を見つけます。
しかし、オプション3が最善のアプローチだと思います。 ただし、 @ gaearonが提案する
私の提案は次のようになります:
<github-icon icon={myDynamicIcon}/>
属性(toString())を意味します。
<github-icon icon:={myDynamicIcon}/>
つまり、SSR中は無視しますが、クライアントをオブジェクトプロパティにバインドします(ハイドレイト後)。
では、シナリオ(いくつか?)についてはどうですか?Reactチームは解決に興味がありますか? 私が最初に考えたのは、2つのコロンなど、他の印章だけでした。
<github-icon icon::={myDynamicIcon}/> //Not my final suggestion!
つまり、SSR中に、JSON.stringifyプロパティがレンダリングされたHTMLの属性として設定され、バインドされているプロパティがハイドレーション後に変更されたときにクライアントにオブジェクトとして渡されます。
これは、複合名をどうするかというトリッキーな状況を残します。 つまり、次のように設定した場合:
<github-icon iconProps::={myDynamicIconProp}/> //Not my final suggestion!
プロパティ名iconPropsに対応する属性がicon-propsである必要があることは、過去には議論の余地がありませんでした。
おそらくこれは、これらのWebコンポーネントの一部が、変更なしで、属性にダッシュを含めることができないプラットフォームに組み込まれる可能性があるという懸念のために、より議論の余地があります(ただし、プロパティはキャメルケースにすることができます)。 私の知る限り、JSONデシリアライズを介して複雑なオブジェクトを渡すことを可能にするネイティブ要素はまだありませんが、将来必要が生じても驚かないでしょう。 では、Reactはダッシュを挿入するタイミングをどのように知るのでしょうか?
私が思いつくことができる唯一の(醜い?)提案は:
<github-icon icon-props:iconProps={myDynamicIconProp}/>
つまり、サーバーでは、シリアル化後に属性icon-propsを使用し、クライアントでは、プロパティiconPropsを使用して、オブジェクトを直接渡します。
ハイブリッド属性/プロパティのペアを可能にする、より詳細な表記のもう1つの(ロングショット?)潜在的な利点は次のとおりです。特に、対応する属性ではなく、ネイティブ要素のプロパティを繰り返し設定する方が少し速い場合があります。文字列ではないプロパティ。 もしそうなら、Reactは現在サーバー上の属性とクライアント上のプロパティを使用していますか? そうでない場合、それは翻訳の難しさの同じ問題のためであり、この表記法はそれを解決しますか?
@bahrus簡単にできると思います
<my-element attr='using-quotes' property={thisIsAnObject} />
具体的な例で問題を説明するのが最善だと思います。
HTMLフォーム要素にはいくつかの属性があります。 「複合名」を持つものはすべて一貫した命名パターンに従っているようには見えません-一般的にはすべて小文字で区切り文字はありませんが、ダッシュ区切り文字がある場合もあります-たとえば「accept-charset」、場合によってはそうではありません- -「novalidate」。
対応するJSプロパティ名も、優れたユニバーサルパターンに適合しません-acceptCharset、noValidate。 noValidateプロパティ/ novalidate属性はブール値であるため、クライアントでは、myForm.noValidate = trueではなくmyForm.setAttribute( 'novalidate'、 '')を実行するのは無駄です(私は想像します)。
ただし、サーバーでは、DOMの文字列表現を送信するため、myForm.noValidate = trueを設定しても意味がありません。そのため、次の属性を使用する必要があります。
<form novalidate={shouldNotValidate}>
実際、React / JSXがブール属性を条件付きで固定されたます。 私がとても大胆かもしれないとしたら、これはReact / JSXが改善できる別の領域のようで、このRFCの一部としてDOMが機能する(厄介な)方法と完全に互換性がありますか?
開発者がパフォーマンスを犠牲にすることなく、サーバー(属性を介して)とクライアント(プロパティを介して)を完全に制御できるように、これらすべてのシナリオをどのように表すことができますか? novalidateのようなブール値のこの場合、私は提案します:
<form novalidate:noValidate?={shouldNotValidate}/>
ReactがDOMを完全にサポートしていれば、それ自体が乱雑で、可能な限りパフォーマンスの高い方法で、カスタム要素をサポートするのに大いに役立つと思います。カスタム要素もおそらく命名パターンであまり一貫性がありません。
サーバー上のJSON.stringifyを介してオブジェクトプロパティを属性にオプションでシリアル化するためのサポートを追加することは、ReactおよびWebコンポーネントにとって追加の大きなwin-winになると私には思えます。
それとも私は何かが足りないのですか? ( @eavichay 、あなたの例に従わずに、これらのシナリオを最もよく表現することをどのように提案しますか)。
最も参考になるコメント
皆さん、待っている間に、Reacthttps : //www.npmjs.com/package/reactify-wcでWebコンポーネントをラップするためのシムを作成しました
これがお役に立てば幸いです
(これはOSSへの私の最初の進出であり、私のオフィスから何かをオープンソース化した最初の1つです。建設的な批判は大歓迎です😄)