React:创建和引用动态组件引用
React: creating and referencing dynamic component refs
我正在尝试跟踪任意数量的子组件。
通常你只会引用 this.refs.refName,但在我的情况下,我需要跟踪任意数量的引用。
这是一个简明的例子:
var NamesList = React.createClass({
getAllNames: function() {
// Somehow return an array of names...
var names = [];
this.refs.????.forEach(function (span) {
names.push(span.textContent);
})
},
render: function() {
var names = ['jack','fred','bob','carl'];
var spans = [];
names.forEach(function (name) {
spans.push(<span contentEditable={true} ref='?????'>name</span>);
});
return (
<div>
{spans}
</div>;
);
}
});
ReactDOM.render(<NamesList></NamesList>, mountNode);
如果我处理问题的方式有误,请告诉我。我想要的结果是将数据从 RESTful 服务传递到 React 组件,允许用户编辑该数据,并在需要时再次导出它。我一直无法在 React refs 文档中找到这个问题的答案。
1.快速而肮脏的解决方案:通过容器组件上的 ref 读取名称
读取所有名称的一种方法是在容器上放置一个 ref,并在 childNode 跨度上读取文本内容。
componentDidMount: function() {
var elem = this.refs.container.getDOMNode();
var nameNodes = elem.children;
var names = [];
for (var i=0; i<nameNodes.length; i++) {
names.push(nameNodes[i].textContent);
}
console.log(names);
},
您可以找到 Working codepen of this here.
警告:上面的代码很脏:用户可以更改跨度的内容,而无需对 DOM 更改做出反应。这是一个 (非常)糟糕的主意。
2。清洁剂
因此您将需要状态:用户可以更改 span 的内容,并且 React 需要了解它。
因为您还需要所有(新)编辑名称的数组,所以此状态需要驻留在容器级别。
这是一个纯 <EditableSpan>
组件的解决方案,每次更改名称时都会调用其父级的方法。
var EditableSpan = React.createClass({
onChange: function() {
var newContent = event.target.textContent;
this.props.onChange(this.props.index, newContent);
},
render: function() {
return <span
contentEditable={true}
onInput={this.onChange}>
{this.props.name}</span>
}
});
请注意,这个更简洁的解决方案不再使用 refs,因为不需要它们:已知所有数据都会做出反应,因此 React 不需要 refs 来读取 DOM。相反,它会在每次更改时读取 event.target
,以更新容器状态。
您可以在此处找到 full working codepen。
警告:对于此解决方案,我添加了快速而肮脏的 keys
(名称)。 React 需要唯一的键(而不是索引)。由于不能保证列表中的名称是唯一的,因此您可能需要另一个更智能的解决方案(创建 ID 或时间戳即可)。
以下将每个跨度的引用保存在一个名为 this.spans
的数组中
这是可行的,因为每个跨度都使用 addSpanRef
方法将自己添加到 refs 数组。
getAllNames
然后遍历所有引用的 span 并获取它们的 textContent。
如果您有子组件(而不是跨度),则可以在这些子节点上调用方法!
var NamesList = React.createClass({
// returns an array of names
getAllNames() {
return this.spans.map((span) => span.textContent);
},
// Add to our spans refs array
addSpanRef (node) {
this.spans = [...this.spans, node];
},
render: function() {
this.spans = []; // create the spans refs array
var names = ['jack','fred','bob','carl'];
// Save a ref to "this" for the forEach loop
var thisRef = this;
names.forEach(function (name) {
spans.push(<span contentEditable={true} ref={thisRef.addSpanRef}>name</span>);
});
return (
<div>
{spans}
</div>;
);
}
});
ReactDOM.render(<NamesList></NamesList>, mountNode);
这可能是我发现的创建动态引用的最简单方法。
此外,此解决方案也适用于 TypeScript,没有任何问题。
const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />
class Parent extends Component {
setRef = (key, ref) => {
this[key] = ref; // Once this function fires, I know about my child :)
};
render(){
return (
{myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
)
}
}
无论如何希望这对某人有所帮助。
我正在尝试跟踪任意数量的子组件。
通常你只会引用 this.refs.refName,但在我的情况下,我需要跟踪任意数量的引用。
这是一个简明的例子:
var NamesList = React.createClass({
getAllNames: function() {
// Somehow return an array of names...
var names = [];
this.refs.????.forEach(function (span) {
names.push(span.textContent);
})
},
render: function() {
var names = ['jack','fred','bob','carl'];
var spans = [];
names.forEach(function (name) {
spans.push(<span contentEditable={true} ref='?????'>name</span>);
});
return (
<div>
{spans}
</div>;
);
}
});
ReactDOM.render(<NamesList></NamesList>, mountNode);
如果我处理问题的方式有误,请告诉我。我想要的结果是将数据从 RESTful 服务传递到 React 组件,允许用户编辑该数据,并在需要时再次导出它。我一直无法在 React refs 文档中找到这个问题的答案。
1.快速而肮脏的解决方案:通过容器组件上的 ref 读取名称
读取所有名称的一种方法是在容器上放置一个 ref,并在 childNode 跨度上读取文本内容。
componentDidMount: function() {
var elem = this.refs.container.getDOMNode();
var nameNodes = elem.children;
var names = [];
for (var i=0; i<nameNodes.length; i++) {
names.push(nameNodes[i].textContent);
}
console.log(names);
},
您可以找到 Working codepen of this here.
警告:上面的代码很脏:用户可以更改跨度的内容,而无需对 DOM 更改做出反应。这是一个 (非常)糟糕的主意。
2。清洁剂
因此您将需要状态:用户可以更改 span 的内容,并且 React 需要了解它。
因为您还需要所有(新)编辑名称的数组,所以此状态需要驻留在容器级别。
这是一个纯 <EditableSpan>
组件的解决方案,每次更改名称时都会调用其父级的方法。
var EditableSpan = React.createClass({
onChange: function() {
var newContent = event.target.textContent;
this.props.onChange(this.props.index, newContent);
},
render: function() {
return <span
contentEditable={true}
onInput={this.onChange}>
{this.props.name}</span>
}
});
请注意,这个更简洁的解决方案不再使用 refs,因为不需要它们:已知所有数据都会做出反应,因此 React 不需要 refs 来读取 DOM。相反,它会在每次更改时读取 event.target
,以更新容器状态。
您可以在此处找到 full working codepen。
警告:对于此解决方案,我添加了快速而肮脏的 keys
(名称)。 React 需要唯一的键(而不是索引)。由于不能保证列表中的名称是唯一的,因此您可能需要另一个更智能的解决方案(创建 ID 或时间戳即可)。
以下将每个跨度的引用保存在一个名为 this.spans
这是可行的,因为每个跨度都使用 addSpanRef
方法将自己添加到 refs 数组。
getAllNames
然后遍历所有引用的 span 并获取它们的 textContent。
如果您有子组件(而不是跨度),则可以在这些子节点上调用方法!
var NamesList = React.createClass({
// returns an array of names
getAllNames() {
return this.spans.map((span) => span.textContent);
},
// Add to our spans refs array
addSpanRef (node) {
this.spans = [...this.spans, node];
},
render: function() {
this.spans = []; // create the spans refs array
var names = ['jack','fred','bob','carl'];
// Save a ref to "this" for the forEach loop
var thisRef = this;
names.forEach(function (name) {
spans.push(<span contentEditable={true} ref={thisRef.addSpanRef}>name</span>);
});
return (
<div>
{spans}
</div>;
);
}
});
ReactDOM.render(<NamesList></NamesList>, mountNode);
这可能是我发现的创建动态引用的最简单方法。
此外,此解决方案也适用于 TypeScript,没有任何问题。
const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />
class Parent extends Component {
setRef = (key, ref) => {
this[key] = ref; // Once this function fires, I know about my child :)
};
render(){
return (
{myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
)
}
}
无论如何希望这对某人有所帮助。