将事件处理程序动态添加到 React.DOM 元素 [英] Add event handler to React.DOM element dynamically

查看:45
本文介绍了将事件处理程序动态添加到 React.DOM 元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 RadioButtonGroup 组件,它类似于单选输入但带有按钮:

如果使用组件像这样简单就好了:

var SelectThing = React.createClass({渲染:函数渲染(){//我不想为每个按钮元素添加 onClick 处理程序//在 RadioButtonGroup 组件之外返回 (<RadioButtonGroup onChange={this._onActiveChange}><button>东西1</button><button>东西2</button><button>东西3</button></RadioButtonGroup>)},_onActiveChange: 函数 _onActiveChange(index) {console.log('你点击了带有索引的按钮:', index);}});

实际问题:如何使用 React 最优雅地实现这一目标?(我发现 另一个类似的问题,但它并没有完全回答这个问题.

我的第一个直觉是在组件内添加和删除 onClick 处理程序,以从组件的用户那里删除样板代码.我想到的另一个选择是给例如<p> 元素而不是按钮元素,并将它们放在将在 RadioButtonGroup 组件内创建的按钮元素中.我不太喜欢后者,因为与传递按钮相比,它在语义上没有那么大的意义.

以下是 (显然不工作) 组件现在的样子:

//带按钮的单选输入//http://getbootstrap.com/javascript/#buttons-checkbox-radiovar RadioButtonGroup = React.createClass({getInitialState: 函数 getInitialState() {返回 {活动:this.props.active ||0};},componentWillMount: 函数 componentWillMount() {var 按钮 = this.props.children;button[this.props.active].className += 'active';var self = this;按钮.forEach(功能(按钮,索引){//如何为虚拟 dom 动态设置 onclick 处理程序//在 JSX 中创建的元素?button.addEventListener('onClick', function(event) {self._onAnyButtonClick(index, event);}});},componentWillUnmount: 函数 componentWillUnmount() {var 按钮 = this.props.children;按钮.forEach(功能(按钮,索引){button.removeEventListener('onClick');});},渲染:函数渲染(){返回 (<div className="radio-button-group">{纽扣}

)},_onAnyButtonClick: 函数 _onAnyButtonClick(index, event) {this.setState({活动:索引});this.props.onChange(index);}});

解决方案

您不想弄乱每个按钮上的单击处理程序,只需监听容器上的单击即可.然后根据点击的孩子更新状态.

此外,使用 React 最好将所有 DOM 内容保留在渲染函数中.在本例中,定义元素的类名.

这是如何工作的:

var RadioButtonGroup = React.createClass({getInitialState: 函数 getInitialState() {返回 {活动:this.props.active ||0};},clickHandler: 函数 clickHandler(e) {//获取一个 DOM 元素数组//然后查找被点击的元素var 节点 = Array.prototype.slice.call( e.currentTarget.children );var index = nodes.indexOf( e.target );this.setState({ active: index });},渲染:函数渲染(){var 按钮 = this.children.map(function(child, i) {if (i === this.state.active) child.props.className += 'active';返回孩子;}, 这);返回 (<div className="radio-button-group" onClick={ this.clickHandler }>{ 纽扣 }

)}});

I'm working with a RadioButtonGroup component which is like radio input but with buttons:

It would be good if using the component was easy like this:

var SelectThing = React.createClass({
    render: function render() {
        // I would not like to add onClick handler to every button element
        // outside the RadioButtonGroup component
        return (
            <RadioButtonGroup onChange={this._onActiveChange}>
                <button>Thing 1</button>
                <button>Thing 2</button>
                <button>Thing 3</button>
            </RadioButtonGroup>
        )
    },

    _onActiveChange: function _onActiveChange(index) {
        console.log('You clicked button with index:', index);
    }
});

The actual question: How can I achieve that the most elegantly with React? (I found another similar question but it doesn't exactly answer to this).

My first intuition was to add and remove the onClick handlers inside the component to remove boiler plate code from the component's user. Another option that comes to my mind is to give e.g. <p> elements instead of button elements and put them inside button elements which would be created inside the RadioButtonGroup component. I don't like the latter that much because it doesn't make that much sense semantically compared to passing buttons.

Here's what the (obviously not working) component looks like now:

// Radio input with buttons
// http://getbootstrap.com/javascript/#buttons-checkbox-radio
var RadioButtonGroup = React.createClass({
    getInitialState: function getInitialState() {
        return {
            active: this.props.active || 0
        };
    },

    componentWillMount: function componentWillMount() {
        var buttons = this.props.children;
        buttons[this.props.active].className += ' active';

        var self = this;
        buttons.forEach(function(button, index) {
            // How to dynamically set onclick handler for virtual dom
            // element created inside JSX?
            button.addEventListener('onClick', function(event) {
                self._onAnyButtonClick(index, event);
            }
        });
    },

    componentWillUnmount: function componentWillUnmount() {
        var buttons = this.props.children;

        buttons.forEach(function(button, index) {
            button.removeEventListener('onClick');
        });  
    },

    render: function render() {
        return (
            <div className="radio-button-group">
                {buttons}
            </div>
        )
    },

    _onAnyButtonClick: function _onAnyButtonClick(index, event) {
        this.setState({
            active: index
        });

        this.props.onChange(index);
    }
});

解决方案

You don't want to mess with click handlers on each button, just listen for the click on the container. Then update the state based on which child is clicked.

Also, with React it's best to keep all of your DOM stuff in the render function. In this case, defining an element's class name.

Here's how this could work:

var RadioButtonGroup = React.createClass({
    getInitialState: function getInitialState() {
        return {
            active: this.props.active || 0
        };
    },

    clickHandler: function clickHandler(e) {
        // Getting an array of DOM elements
        // Then finding which element was clicked
        var nodes = Array.prototype.slice.call( e.currentTarget.children );
        var index = nodes.indexOf( e.target );
        this.setState({ active: index });
    },

    render: function render() {
        var buttons = this.children.map(function(child, i) {
            if (i === this.state.active) child.props.className += ' active';
            return child;
        }, this);

        return (
            <div className="radio-button-group" onClick={ this.clickHandler }>
                { buttons }
            </div>
        )
    }
});

这篇关于将事件处理程序动态添加到 React.DOM 元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆