Javascript 在 React JS 中创建 <select> 元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25793918/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating <select> elements in React JS
提问by George Oblapenko
I'm rewriting the UI for my web-app in react.js, and I'm a bit stumped by the following problem.
我正在 react.js 中为我的 web 应用程序重写 UI,但我有点被以下问题难住了。
I have a page which displays data obtained via an AJAX request, and below that, a form to submit new data is displayed. All good.
我有一个页面,显示通过 AJAX 请求获取的数据,在该页面下方,显示提交新数据的表单。都好。
Now, I want to add a <select>element to the form, and fetch the values from a different location (url).
现在,我想向<select>表单添加一个元素,并从不同的位置 (url) 获取值。
The current code (without the <select>) looks like this (simplified a bit, but all the working details are the same; it mostly follows the tutorial on the react.js website):
当前代码(没有<select>)看起来像这样(简化了一点,但所有的工作细节都是一样的;它主要遵循 react.js 网站上的教程):
var tasks_link = $('#tasks_link');
var getDataMixin = {
loadDataFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadDataFromServer();
}
};
var sendDataMixin = {
handleDataSubmit: function(senddata) {
$.ajax({
url: this.props.url,
dataType: 'json',
contentType: 'application/json',
type: 'POST',
data: senddata,
success: function(data) {
var curr_d = this.state.data;
var curr_d_new = curr_d.concat([data]);
this.setState({data: curr_d_new});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
}
};
var taskForm = React.createClass({
handleSubmit: function() {
var name = this.refs.task_name.getDOMNode().value.trim();
if (!name) {
return false;
}
this.props.onTaskSubmit(JSON.stringify({name: name}));
this.refs.task_name.getDOMNode().value = '';
return false;
},
render: function () {
return (
<form className="well base_well new_task_well" onSubmit={this.handleSubmit}>
<div className="form-group">
<div className="input-group">
<span className="input-group-addon no_radius">Task name</span>
<input type="text" className="form-control no_radius" id="add_new_project_input" ref="task_name"/>
</div>
</div>
<button type="button" className="btn btn-default no_radius add_button" id="add_new_task_btn" type="submit">Add task</button>
</form>
);
}
});
var taskBox = React.createClass({
mixins: [getDataMixin, sendDataMixin],
render: function () {
return (
<div id="project_box" className="taskBox"> <taskList data={this.state.data} />
<taskForm onTaskSubmit={this.handleDataSubmit}/> </div>
);
}
});
tasks_link.click(function() {
React.renderComponent(
<taskBox url="/api/tasks/" />,
document.getElementById('content_container')
);
});
Now, I can add a selectelement by adding a getDataMixinto TaskForm, fetching the data and building a list of possible options, but I will need to have forms with many lists, and the approach doesn't seem to scale (due to naming collisions; or I'll need to use something other than mixins).
现在,我可以select通过添加getDataMixinto来添加一个元素TaskForm,获取数据并构建一个可能选项的列表,但我需要有许多列表的表单,并且该方法似乎无法扩展(由于命名冲突;或者我需要使用mixin以外的东西)。
So I though of creating a separate React class, which would just have the getDataMixin, receive the API url via the parent setting its props, and render the <select>element; and use this class inside the form.
But I have no idea how to access the selected value (since a parent cannot access it's child's refs).
So I need another way to pass the selected value "up".
所以我虽然创建了一个单独的React class,它只会有getDataMixin,通过父设置接收 API url props,并呈现<select>元素;并在表单中使用这个类。但我不知道如何访问选定的值(因为父级无法访问它的子级refs)。所以我需要另一种方法来“向上”传递选定的值。
Or, in case this isn't possible, a nudge in the correct direction – I don't want to end up with a ton of un-reusable code (part of the reason why I switched to react was to use mixins and keep the code to a sane and readable minimum).
或者,如果这是不可能的,朝正确的方向轻推——我不想最终得到大量不可重用的代码(我切换到 react 的部分原因是使用 mixins 并保持代码到一个理智和可读的最低限度)。
回答by Mike Driver
A parent can access it's child's refs as long as you set the child as a ref inside the parent, you can access any refs inside that child. So for example something like this.refs.childRef.refs.nestedChildRef. However this is a really bad idea unless you are just reading information (and handling errors such as the refs not existing correctly since the parent doesn't know if the child's ref is set correctly).
父级可以访问它的子级引用,只要您将子级设置为父级内的引用,您就可以访问该子级内的任何引用。所以例如像this.refs.childRef.refs.nestedChildRef. 然而,这是一个非常糟糕的主意,除非您只是在阅读信息(并处理诸如 ref 不正确存在的错误,因为父级不知道子级的 ref 设置是否正确)。
But luckily there is a very simple solution. You are right, you will want to create a child component which gets it's own data, rather than a mixin. But how you handle giving the selected item back to the parent is simply pass an onChange function from the parent like you would to an in-built <select>in react.
但幸运的是,有一个非常简单的解决方案。你是对的,你会想要创建一个子组件来获取它自己的数据,而不是一个 mixin。但是,您如何处理将所选项目返回给父项的方式只是将一个 onChange 函数从父项传递给内置<select>的反应。
Here's an example of this parent child relationship:
这是这种父子关系的示例:
var MyParent = React.createClass({
getInitialState: function() {
return {
childSelectValue: undefined
}
},
changeHandler: function(e) {
this.setState({
childSelectValue: e.target.value
})
},
render: function() {
return (
<div>
<MySelect
url="http://foo.bar"
value={this.state.childSelectValue}
onChange={this.changeHandler}
/>
</div>
)
}
});
var MySelect = React.createClass({
propTypes: {
url: React.PropTypes.string.isRequired
},
getInitialState: function() {
return {
options: []
}
},
componentDidMount: function() {
// get your data
$.ajax({
url: this.props.url,
success: this.successHandler
})
},
successHandler: function(data) {
// assuming data is an array of {name: "foo", value: "bar"}
for (var i = 0; i < data.length; i++) {
var option = data[i];
this.state.options.push(
<option key={i} value={option.value}>{option.name}</option>
);
}
this.forceUpdate();
},
render: function() {
return this.transferPropsTo(
<select>{this.state.options}</select>
)
}
});
The above example shows a parent component MyParentincluding a child component MySelectwhich it passes a url to, along with any other props that are valid for a standard react <select>element. Using react's built in this.transferPropsTo()function to transfer all props over to the child's <select>element in it's render function.
上面的例子显示了一个父组件,它MyParent包含一个子组件MySelect,它传递一个 url,以及任何其他对标准 react<select>元素有效的 props 。使用 react 的内置this.transferPropsTo()函数将所有道具转移到<select>其渲染函数中的子元素。
This means that the parent defining changeHandleras the onChangehandler for MySelectpasses this function directly to the child's <select>element. So when the select changes, the event gets handled by the parent instead of the child. And by the way this is a prefectly legal and legit way to do things in React - since it's still following the top down philosophy. If you think about it, when you use a normal built-in <select>from react, this is exactly what's going on. onChangeis just a property for <select>.
这意味着定义changeHandler为onChange处理程序的父元素MySelect直接将此函数传递给子<select>元素的元素。So when the select changes, the event gets handled by the parent instead of the child. 顺便说一下,这是在 React 中做事的一种完全合法和合法的方式——因为它仍然遵循自上而下的哲学。如果你考虑一下,当你使用一个普通的内建<select>from react 时,这正是发生的事情。 onChange只是 的一个属性<select>。
It's also worth noting that if you like, you can "hyHyman" the change handler to add your own custom logic. For example what I tend to do is wrap my <input type="text" />fields with a custom input component that takes any and all valid <input>props, but also takes validatorfunction as a property which allows me to define a function that returns true/false based on the value inputted in to the <input>field. I can do this by defining onChangein the parent, for the wrapper child, but then in the child I define my own onChangeinternally which checks for this.props.onChangeto be defined, and a function, then runs my validator and passes the event chain back up to the parent by calling this.props.onChange(e, valid). Giving the parent the very same event object in it's onChangehandler, but also with an added boolean validargument. Anyway, I digress....
还值得注意的是,如果您愿意,可以“劫持”更改处理程序以添加您自己的自定义逻辑。例如,我倾向于做的是<input type="text" />用一个自定义输入组件包装我的字段,该组件接受任何和所有有效的<input>道具,但也将validator函数作为一个属性,它允许我定义一个基于输入的值返回真/假的函数该<input>领域。我可以通过onChange在父级中为包装子级定义来做到这一点,但是在子级中我定义了我自己的onChange内部检查this.props.onChange要定义的函数和一个函数,然后运行我的验证器并将事件链传递回父级通过调用this.props.onChange(e, valid). 在其onChange处理程序中为父级提供完全相同的事件对象,但还添加了布尔值valid争论。无论如何,我离题了......
Hope this helps you out :)
希望这可以帮助你 :)

