React.js 2 路绑定:valueLink 中的两层深度路径
-
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
, ,您可以使用非 mixin 版本,例如:
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/
其他提示
如果基本 mixin 不能满足您的需求,您可以实现自己的 mixin。
看看这个 mixin 是如何实现的:
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);
};
}
所以你绝对应该尝试编写自己的 mixin。如果您的状态有一个复杂的对象并且您想通过对象 API 修改它,这会非常有用。
我在不使用 value-link 插件的情况下做到了这一点。
这是一个演示: http://wingspan.github.io/wingspan-forms/examples/form-twins/
秘诀是只定义一个 onChange 函数:
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,你可以用它来玩
这是解释如何处理此类事情的教程。
长话短说:
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>
})
我采取了一种不同的方法,它不使用 mixins 并且不会自动改变状态