React.js の双方向バインディング:valueLink の 2 レベルの深いパス
-
22-12-2019 - |
質問
私の状態は次のとおりです。
[
{type: "translateX", x: 10},
{type: "scaleX", x: 1.2}
]
使用しています 双方向バインディングヘルパー 有効なキー文字列を提供できません linkState
:
this.state.map(function(item, i) {
return <div><input valueLink={this.linkState( ??? )}></div>
}
できたらいいですね this.linkState
次のようないくつかのクエリ構文を受け入れます。 "0.type"
取得する "translateX"
私の例から。
回避策はありますか?
私が書いた DeepLinkState ミックスイン これは、React.addons.LinkedStateMixin のドロップイン代替品です。使用例:
this.state.map(function(item, i) {
return <div><input valueLink={this.linkState([i, "x"])}></div>
}
linkState("0.x")
という構文も使用できます。
解決
編集:
私はその深い道に気づきました LinkedState
とても素敵なので実装してみます。
コード: https://gist.github.com/tungd/8367229
使用法: http://jsfiddle.net/uHm6k/3/
文書に記載されているように、 LinkedState
ラッパーです onChange/setState
単純なケースを対象としています。いつでも全文を書くことができます onChange/setState
あなたが望むものを達成するために。本当にこだわりたいなら LinkedState
, 、たとえば、非ミックスイン バージョンを使用できます。
getInitialState: function() {
return { values: [
{ type: "translateX", x: 10 },
{ type: "scaleX", x: 1.2 }
]}
},
handleTypeChange: function(i, value) {
this.state.values[i].type = value
this.setState({ values: this.state.values })
},
render: function() {
...
this.state.values.map(function(item, i) {
var typeLink = {
value: this.state.values[i].type,
requestChange: this.handleTypeChange.bind(null, i)
}
return <div><input valueLink={typeLink}/></div>
}, this)
...
}
これが動作するJSFiddleです: http://jsfiddle.net/srbGL/
他のヒント
基本のミックスインでは満足できない場合は、独自のミックスインを実装できます。
このミックスインがどのように実装されているかを確認してください。
var LinkedStateMixin = {
/**
* Create a ReactLink that's linked to part of this component's state. The
* ReactLink will have the current value of this.state[key] and will call
* setState() when a change is requested.
*
* @param {string} key state key to update. Note: you may want to use keyOf()
* if you're using Google Closure Compiler advanced mode.
* @return {ReactLink} ReactLink instance linking to the state.
*/
linkState: function(key) {
return new ReactLink(
this.state[key],
ReactStateSetters.createStateKeySetter(this, key)
);
}
};
/**
* @param {*} value current value of the link
* @param {function} requestChange callback to request a change
*/
function ReactLink(value, requestChange) {
this.value = value;
this.requestChange = requestChange;
}
https://github.com/facebook/react/blob/fc73bf0a0abf739a9a8e6b1a5197dab113e76f27/src/addons/link/LinkedStateMixin.js https://github.com/facebook/react/blob/fc73bf0a0abf739a9a8e6b1a5197dab113e76f27/src/addons/link/ReactLink.js
したがって、独自のコードを簡単に作成してみることができます linkState
上記を踏まえた機能です。
linkState: function(key,key2) {
return new ReactLink(
this.state[key][key2],
function(newValue) {
this.state[key][key2] = newValue;
}
);
}
私が使用していないことに注意してください ReactStateSetters.createStateKeySetter(this, key)
.
https://github.com/facebook/react/blob/fc73bf0a0abf739a9a8e6b1a5197dab113e76f27/src/core/ReactStateSetters.jsソース コードをもう一度見ると、このメソッドは関数を作成し、キャッシュの最適化をほとんど実行しないことを除いて、それほど多くのことを行っていないことがわかります。
function createStateKeySetter(component, key) {
// Partial state is allocated outside of the function closure so it can be
// reused with every call, avoiding memory allocation when this function
// is called.
var partialState = {};
return function stateKeySetter(value) {
partialState[key] = value;
component.setState(partialState);
};
}
したがって、必ず独自のミックスインを作成してみる必要があります。これは、状態に複雑なオブジェクトがあり、オブジェクト API を通じてそれを変更したい場合に非常に役立ちます。
私はバリューリンクアドオンを使わずにやっています。
これがデモです: http://wingspan.github.io/wingspan-forms/examples/form-twins/
秘密のソースは、onChange 関数を 1 つだけ定義することです。
onChange: function (path, /* more paths,*/ value) {
// clone the prior state
// traverse the tree by the paths and assign the value
this.setState(nextState);
}
次のように使用します。
<input
value={this.state['forms']['0']['firstName']}
onChange={_.partial(this.onChange, 'forms', '0', 'firstName')} />
たくさん持っているなら (value, onChange)
どこにでも渡さなければならないペアがあるため、ReactLink と同様にこれに関する抽象化を定義することは理にかなっているかもしれませんが、私は個人的には ReactLink を使用せずにかなりのところまで到達しました。
同僚と私は最近オープンソース化しました 翼幅フォーム, 、深くネストされた状態を支援する React ライブラリです。私たちはこのアプローチを大いに活用しています。リンクされた状態を含むデモの例は、github ページでさらに見ることができます。
私はそれについてブログ投稿を書きました: http://blog.sendsonar.com/2015/08/04/angular-like-deep-path-data-bindings-in-react/
ただし、基本的には、親の「状態」と深いパスを受け入れる新しいコンポーネントを作成したので、追加のコードを記述する必要はありません。
<MagicInput binding={[this, 'account.owner.email']} />
JSFiddle もあるので遊んでみてください
このようなことを処理する方法を説明するチュートリアルは次のとおりです。
TL;DR:
0) 標準リンクを使用しないでください。使用 これら.
1) 状態を次のように変更します。
collection : [
{type: "translateX", x: 10},
{type: "scaleX", x: 1.2}
]
2) へのリンクを取得します。 collection
:
var collectionLink = Link.state( this, 'collection' );
3) 要素へのリンクを反復処理します。
collectionLink.map(function( itemLink, i ) {
return <div><input valueLink={itemLink}></div>
})
私はミックスインを使用せず、状態を自動的に変更しない別のアプローチを採用しました。