草庐IT

javascript - 在 React JS 中创建 <select> 元素

coder 2024-05-10 原文

我正在用 react.js 重写我的网络应用程序的 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')
        );
    });

现在,我可以添加 select通过添加 getDataMixin 元素至 TaskForm ,获取数据并构建可能选项的列表,但我需要有包含许多列表的表单,而且该方法似乎无法扩展(由于命名冲突;或者我需要使用 mixin 以外的东西) .

所以我想创建一个单独的 React class ,它只有 getDataMixin ,通过设置其 props 的父级接收 API url ,并呈现 <select>元素;并在表单中使用此类。 但我不知道如何访问选定的值(因为 parent 无法访问它的 child 的 refs )。 所以我需要另一种方法来“向上”传递所选值。

或者,万一这是不可能的,向正确的方向轻推——我不想以大量不可重用的代码结束(我转而使用 React 的部分原因是使用 mixins并将代码保持在合理和可读的最低限度)。

最佳答案

只要您将 child 设置为父级内部的 ref,父级就可以访问其子级的 refs,您可以访问该子级内部的任何 refs。因此,例如 this.refs.childRef.refs.nestedChildRef .然而,这是一个非常糟糕的主意,除非您只是阅读信息(并处理错误,例如 refs 不正确存在,因为 parent 不知道 child 的 ref 是否设置正确)。

但幸运的是,有一个非常简单的解决方案。你是对的,你会想要创建一个子组件来获取它自己的数据,而不是混合。但是,如何处理将所选项目返回给父级的方式,就像将 onChange 函数从父级传递给内置的 <select> 一样。在 react 中。

这是这种父子关系的示例:

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,以及对标准 react 有效的任何其他 Prop <select>元素。使用内置的 React this.transferPropsTo()将所有 Prop 转移到 child 的功能 <select>渲染函数中的元素。

这意味着父定义 changeHandler作为 onChange MySelect 的处理程序将此函数直接传递给 child 的 <select>元素。 So when the select changes, the event gets handled by the parent instead of the child.顺便说一句,这是在 React 中做事的完全合法和合法的方式——因为它仍然遵循自上而下的哲学。如果您考虑一下,当您使用普通的内置 <select> 时从 react 来看,这正是正在发生的事情。 onChange只是 <select> 的属性.

还值得注意的是,如果您愿意,您可以“劫持”更改处理程序以添加您自己的自定义逻辑。例如,我倾向于做的是包装我的 <input type="text" />具有自定义输入组件的字段,该组件接受任何和所有有效的 <input> Prop ,还需要validator函数作为一个属性,它允许我定义一个函数,该函数根据输入到 <input> 的值返回 true/false field 。我可以通过定义 onChange 来做到这一点在父级中,对于包装器子级,但在子级中我定义了自己的 onChange在内部检查 this.props.onChange要定义的函数,然后运行我的验证器并通过调用 this.props.onChange(e, valid) 将事件链传递回父级.在 onChange 中为父级提供完全相同的事件对象处理程序,还添加了一个 bool 值 valid争论。无论如何,我离题了....

希望这对你有帮助:)

关于javascript - 在 React JS 中创建 <select> 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25793918/

有关javascript - 在 React JS 中创建 <select> 元素的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  3. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  4. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  5. ruby - 如何在 Ruby 中创建无类 DSL? - 2

    我正在尝试找出如何为我的Ruby项目创建一种“无类DSL”,类似于在Cucumber步骤定义文件中定义步骤定义或在Sinatra应用程序中定义路由。例如,我想要一个文件,其中调用了我的所有DSL函数:#sample.rbwhen_string_matches/hello(.+)/do|name|call_another_method(name)end我认为用我的项目特有的一堆方法污染全局(内核)命名空间是一种不好的做法。因此方法when_string_matches和call_another_method将在我的库中定义,并且sample.rb文件将以某种方式在我的DSL方法的上下文中

  6. ruby - 在哈希的键数组中追加元素 - 2

    查看我的Ruby代码:h=Hash.new([])h[0]=:word1h[1]=h[1]输出是:Hash={0=>:word1,1=>[:word2,:word3],2=>[:word2,:word3]}我希望有Hash={0=>:word1,1=>[:word2],2=>[:word3]}为什么要附加第二个哈希元素(数组)?如何将新数组元素附加到第三个哈希元素? 最佳答案 如果您提供单个值作为Hash.new的参数(例如Hash.new([]),完全相同的对象将用作每个缺失键的默认值。这就是您所拥有的,那是你不想要的。您可以改用

  7. ruby-on-rails - 如何在 Rails 3 中创建自定义脚手架生成器? - 2

    有这些railscast。http://railscasts.com/episodes/218-making-generators-in-rails-3有了这个,你就会知道如何创建样式表和脚手架生成器。http://railscasts.com/episodes/216-generators-in-rails-3通过这个,您可以了解如何添加一些文件来修改脚手架View。我想把两者结合起来。我想创建一个生成器,它也可以创建脚手架View。有点像RyanBates漂亮的生成器或web_app_themegem(https://github.com/pilu/web-app-theme)。我

  8. ruby - 为什么在 ruby​​ 中创建 Rational 不需要新方法 - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Rubysyntaxquestion:Rational(a,b)andRational.new!(a,b)我正在阅读ruby镐书,我对创建有理数的语法感到困惑。Rational(3,4)*Rational(1,2)产生=>3/8为什么Rational不需要new方法(我还注意到例如我可以在没有new方法的情况下创建字符串)?

  9. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  10. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

随机推荐