【问题标题】:React (Facebook): managed state of controlled checkboxesReact (Facebook):受控复选框的托管状态
【发布时间】:2014-02-05 15:41:48
【问题描述】:

我在尝试使用React 创建一个选择和取消选择其他单个复选框(全选/全选)的复选框时遇到了一点问题。我阅读了http://facebook.github.io/react/docs/forms.html 并发现受控不受控 <input>s 之间存在差异。我的测试代码如下:

var Test = React.createClass({
    getInitialState: function() {
        return {
            data: [
                { id: 1, selected: false },
                { id: 2, selected: false },
                { id: 3, selected: false },
                { id: 4, selected: false }
            ]
        };
    },
    render: function() {
        var checks = this.state.data.map(function(d) {
            return (
                <div>
                    <input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} />
                    {d.id}
                    <br />
                </div>
            );
        });
        return (
            <form>
                <input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector
                <br />
                {checks}
            </form>
        );
    },
    __changeSelection: function(e) {
        var id = e.target.getAttribute('data-id');
        var state = this.state.data.map(function(d) {
            return {
                id: d.id,
                selected: (d.id === id ? !d.selected : d.selected)
            };
        });

        this.setState({ data: state });

    },
    __changeAllChecks: function(e) {
        var value = this.refs.globalSelector.getDOMNode().checked;
        var state = this.state.data.map(function(d) {
            return { id: d.id, selected: value };
        });

        this.setState({ data: state });
    }
});

React.renderComponent(<Test />, document.getElementById('content'));

“全局选择器”按预期工作:选中时,所有其他检查都被选中。问题是当单击其他复选框之一时,__changeSelection() 处理程序不会被触发。

我不知道实现这项工作的正确方法是什么。也许 React 模型不是模拟这种交互的最佳模型?我能做什么?

提前致谢

【问题讨论】:

    标签: javascript facebook reactjs


    【解决方案1】:

    在您的render 函数中,checks 映射函数的this 的范围与render 不同,这是您需要的__changeSelection 的范围,因此this.__changeSelection 不会找到__changeSelection 财产。如果在该映射函数的末尾添加.bind(this),则可以将其范围绑定到与render 相同的this

    var checks = this.state.data.map(function(d) {
        return (
            <div>
                <input type="checkbox" data-id={d.id} checked={d.selected} onChange={this.__changeSelection} />
                {d.id}
                <br />
            </div>
        );
    }.bind(this));
    

    附带说明,我只是将id 传递给处理函数,而不是分配数据属性。这将消除在您的处理程序中定位该元素的需要:

    var checks = this.state.data.map(function(d) {
        return (
            <div>
                <input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} />
                {d.id}
                <br />
            </div>
        );
    }.bind(this));
    

    然后更新您的__changeSelection 函数以将id 作为第一个参数传递并删除属性查找行:

    __changeSelection: function(id) {
        var state = this.state.data.map(function(d) {
            return {
                id: d.id,
                selected: (d.id === id ? !d.selected : d.selected)
            };
        });
    
        this.setState({ data: state });
    
    }
    

    这是一个例子,along with a jsfiddle for you to try it out

    /** @jsx React.DOM */
    
    var Test = React.createClass({
        getInitialState: function() {
            return {
                data: [
                    { id: 1, selected: false },
                    { id: 2, selected: false },
                    { id: 3, selected: false },
                    { id: 4, selected: false }
                ]
            };
        },
        render: function() {
            var checks = this.state.data.map(function(d) {
                return (
                    <div>
                        <input type="checkbox" checked={d.selected} onChange={this.__changeSelection.bind(this, d.id)} />
                        {d.id}
                        <br />
                    </div>
                );
            }.bind(this));
            return (
                <form>
                    <input type="checkbox" ref="globalSelector" onChange={this.__changeAllChecks} />Global selector
                    <br />
                    {checks}
                </form>
            );
        },
        __changeSelection: function(id) {
            var state = this.state.data.map(function(d) {
                return {
                    id: d.id,
                    selected: (d.id === id ? !d.selected : d.selected)
                };
            });
    
            this.setState({ data: state });
    
        },
        __changeAllChecks: function() {
            var value = this.refs.globalSelector.getDOMNode().checked;
            var state = this.state.data.map(function(d) {
                return { id: d.id, selected: value };
            });
    
            this.setState({ data: state });
        }
    });
    
    React.renderComponent(<Test />, document.getElementById('content'));
    

    【讨论】:

    • 谢谢,这解决了问题。我完全忘记了“这个”绑定。既然我们在谈论绑定,为什么你使用 this.__changeSelection.bind(this, d.id) 而不是 this.__changeSelection(id)?我承认这种“绑定”对我来说是新事物(现在我正在学习 React)。
    • @matheus-emm 使用this.__changeSelection(id) 会立即调用该函数(例如在渲染时)。我们只想传递函数的引用,以便稍后可以通过onChange 事件调用它。例如,如果你在浏览器控制台中输入console.log,它会打印出函数,但如果你输入console.log(),它会触发实际的函数。 anyFunc.bind(this, arg) 将创建一个绑定到 this 的新函数,并将传入的任何参数添加到原始函数的前面,但不会调用它。
    • 我正在尝试使用checked: @props.checkAll 设置复选框的状态,它按预期工作。但是,设置此属性后,我无法手动选中/取消选中。删除此属性后,我可以手动完成
    • @matheus.emm 您将如何使用extends Component 语法而不是createClass 来完成此操作
    【解决方案2】:

    如果您正在处理复选框,您可以使用checkedLink 属性。这是另一种可能的实现,它使全局复选框受控制(而不是在当前答案中不受控制):

    JsFiddle

    var Test = React.createClass({
    
        getInitialState: function() {
            return {
                globalCheckbox: false,
                data: [
                    { id: 1, selected: false },
                    { id: 2, selected: false },
                    { id: 3, selected: false },
                    { id: 4, selected: false }
                ]
            };
        },
    
        changeCheckForId: function(id,bool) {
            this.setState(
                {
                data: this.state.data.map(function(d) {
                    var newSelected = (d.id === id ? bool : d.selected);
                    return {id: d.id, selected: newSelected};
                }
            )});
        },
    
        changeCheckForAll: function(bool) {
            this.setState({
                    globalCheckbox: true,
                    data: this.state.data.map(function(d) {
                        return {id: d.id, selected: bool};
                    })
            });
        },
    
    
    
        linkCheckbox: function(d) {
          return {
             value: d.selected,
             requestChange: function(bool) { this.changeCheckForId(d.id,bool); }.bind(this)
          };
        },
    
        linkGlobalCheckbox: function() {
          return {
             value: this.state.globalCheckbox,
             requestChange: function(bool) { this.changeCheckForAll(bool); }.bind(this)
          };
        },
    
        render: function() {
            var checks = this.state.data.map(function(d) {
                return (
                    <div>
                        <input key={d.id} type="checkbox" checkedLink={this.linkCheckbox(d)} />
                        {d.id}
                        <br />
                    </div>
                );
            }.bind(this));
    
            return (
                <form>
                    <input type="checkbox" checkedLink={this.linkGlobalCheckbox()} />Global selector
                    <br />
                    {checks}
                </form>
            );
        },
    
    });
    

    如果要变异的状态没有深度嵌套,则使用 checkedLink=this.linkState("checkboxValue")LinkedStateMixin 会更简单(就像这个问题中的情况一样)

    编辑checkedLinkvalueLink 已被弃用,但在之前的 React 版本中被推荐使用。

    【讨论】:

    • 我正在尝试使用checked: @props.checkAll 设置复选框的状态,它按预期工作。但是,设置此属性后,我无法手动选中/取消选中。删除此属性后,我可以手动完成
    • checkedLink 似乎根本不起作用。尽管设置了checkedLink=true,但我看不到复选框被选中
    • @vipin8169 我从来没有说过要使用checkedLink=true 请仔细阅读我的回答,checkedLink 属性需要一个具有2个属性的对象
    猜你喜欢
    • 1970-01-01
    • 2021-02-14
    • 2015-12-15
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 2020-11-27
    相关资源
    最近更新 更多