在 React JS 中创建 <select> 元素
Posted
技术标签:
【中文标题】在 React JS 中创建 <select> 元素【英文标题】:Creating <select> elements in React JS 【发布时间】:2014-11-05 18:49:50 【问题描述】:我正在用 react.js 为我的 web 应用程序重写 UI,但我有点被以下问题难住了。
我有一个显示通过 AJAX 请求获得的数据的页面,在该页面下方显示了一个提交新数据的表单。都很好。
现在,我想在表单中添加一个<select>
元素,并从不同的位置(url)获取值。
当前代码(没有<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')
);
);
现在,我可以通过将getDataMixin
添加到TaskForm
来添加select
元素,获取数据并构建可能选项的列表,但我需要有包含许多列表的表单,并且该方法不' 似乎无法扩展(由于命名冲突;或者我需要使用 mixins 以外的东西)。
所以我想创建一个单独的React class
,它只有getDataMixin
,通过设置其props
的父级接收API url,并渲染<select>
元素;并在表单中使用此类。
但我不知道如何访问选定的值(因为父母无法访问它的孩子的refs
)。
所以我需要另一种方法来“向上”传递所选值。
或者,如果这不可能,请朝正确的方向轻推——我不想最终得到大量不可重用的代码(我改用 react 的部分原因是使用 mixins并将代码保持在合理且可读的最低限度)。
【问题讨论】:
【参考方案1】:只要您将子级设置为父级内部的引用,父级就可以访问其子级的引用,您就可以访问该子级内部的任何引用。例如,this.refs.childRef.refs.nestedChildRef
之类的东西。然而,这是一个非常糟糕的主意,除非您只是在阅读信息(并处理诸如 refs 不正确存在的错误,因为父母不知道孩子的 ref 是否设置正确)。
但幸运的是,有一个非常简单的解决方案。你是对的,你会想要创建一个子组件来获取它自己的数据,而不是一个 mixin。但是,您如何处理将选定项目返回给父级的方式只是将父级的 onChange 函数传递给反应中的内置 <select>
。
以下是这种父子关系的示例:
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>
)
);
上面的例子显示了一个父组件MyParent
,包括一个子组件MySelect
,它传递了一个url,以及任何其他对标准反应<select>
元素有效的props。使用 react 内置的 this.transferPropsTo()
函数将所有道具转移到子渲染函数中的 <select>
元素。
这意味着定义changeHandler
为MySelect
的onChange
处理程序的父级将此函数直接传递给子级的<select>
元素。 So when the select changes, the event gets handled by the parent instead of the child.顺便说一句,这是在 React 中做事的一种完全合法且合法的方式——因为它仍然遵循自上而下的理念。如果您考虑一下,当您使用来自 react 的普通内置 <select>
时,这正是正在发生的事情。 onChange
只是 <select>
的属性。
还值得注意的是,如果您愿意,您可以“劫持”更改处理程序以添加您自己的自定义逻辑。例如,我倾向于使用自定义输入组件包装我的 <input type="text" />
字段,该组件接受任何和所有有效的 <input>
道具,但也将 validator
函数作为属性,它允许我定义一个返回 true 的函数/false 基于在<input>
字段中输入的值。我可以通过在父级中为包装子级定义 onChange
来做到这一点,但是在子级中我在内部定义自己的 onChange
来检查要定义的 this.props.onChange
和一个函数,然后运行我的验证器和通过调用this.props.onChange(e, valid)
将事件链传递回父级。在它的onChange
处理程序中为父级提供完全相同的事件对象,但还添加了一个布尔值valid
参数。反正我跑题了……
希望对你有所帮助:)
【讨论】:
Mike,正如您所写,您的解决方案不会在选择对象上调用渲染,因为您不使用 setState(x) 函数。我修改代码如下创建一个位置数组,var optionsArray = [];,然后更新该数组,最后在循环之后调用:this.setState(options:optionsArray); 很好——这就是我没有在答案中测试代码所得到的结果,尽管我个人更喜欢在直接改变状态对象时使用this.forceUpdate()
。不过大多只是个人喜好。我已经编辑了我的答案以更新它。以上是关于在 React JS 中创建 <select> 元素的主要内容,如果未能解决你的问题,请参考以下文章
React.js。在函数体中创建带参数(和道具将是参数)或引用道具的方法更好吗?