简体   繁体   English

React.js中的动态子级导航(传播事件和属性)

[英]Dynamic children navigation in React.js (propagating events and properties)

One thing I'm still struggling with in React.js is the proper way to handle child event and property propagation. 我仍然在React.js中苦苦挣扎的一件事是处理子事件和属性传播的正确方法。 There are many examples of this being done already, but the implementations are always vastly different. 已经有很多示例可以完成,但是实现总是有很大的不同。 Surely, there is a "right way" to do it... 当然,有一种“正确的方法”来做……

The task is to create a "Nav" component which is made up of "NavItem" components. 任务是创建一个由“ NavItem”组件组成的“ Nav”组件。 Below is the code that I am expecting to work, but it doesn't. 以下是我期望可以使用的代码,但事实并非如此。 The comments explain where I'm having issues. 这些评论说明了我遇到的问题。 Please advise on the best solution and let me know what I'm doing wrong. 请提供最佳解决方案的建议,并让我知道我做错了什么。

Nav.jsx Nav.jsx

var Nav = React.createClass({
    propTypes: {
        active:         React.PropTypes.string,
        onSelect:       React.PropTypes.func
    },
    getInitialState: function () {
        return {
            active: this.props.active
        };
    },
    render: function () {
        return this.transferPropsTo(
            <nav>
                {this.props.children.map(this.renderChild)}
            </nav>
        );
    },
    renderChild: function (child, i) {
        // Here I want to generate a unique 'key' property for each child as well
        // as define a custom onSelect method which will tell the "Nav" component which is
        // the active key.
        return React.addons.cloneWithProps(child, {
            // Here I want to use the 'active' property of the Nav component to drive the
            // the 'active' property of the child.
            active: this.state.active === i ? true, false,
            key: i,
            onSelect: this.handleSelect
        });
    },
    handleSelect: function (event, component) {
        // PROBLEM: Here I want to get the 'key' property of the child. But there seems to be
        // no way to do this.
        var _child_key_ = 'impossible'; 
        this.setState({active: _child_key_});
    }
});

NavItem.jsx NavItem.jsx

var NavItem = React.createClass({
    propTypes: {
        active:     React.PropTypes.string,
        onSelect:   React.PropTypes.func
    },
    getInitialState: function () {
        return {
            active: this.props.active
        };
    },
    render: function () {
        return this.transferPropsTo(
            <a className="{this.state.active ? 'active' : ''}" onClick={this.handleSelect}>
                {this.props.label}
            </a>
        );
    },
    handleSelect: function (event, component) {
        // Propagate the event up to the parent event property.
        if (this.props.handleSelect) this.props.handleSelect(event, component);
    }
});

MyApp.jsx MyApp.jsx

var App = React.createClass({
    render: function () {
        return (
            <Nav>
                <NavItem label="Home" />
                <NavItem label="Page1" />
                <NavItem label="Page2" />
            </Nav>
        );
    }
});

React.renderComponent(new App(), document.body)

I believe this is the most sane way. 我相信这是最理智的方法。

var Nav = React.createClass({
    propTypes: {
        active:         React.PropTypes.string,
        onSelect:       React.PropTypes.func
    },

    // no state
    //getInitialState: function () {},

    render: function () {
        // use React.Children.map because children is opaque
        return this.transferPropsTo(
            <nav>
                {React.Children.map(this.props.children, this.renderChild)}
            </nav>
        );
    },
    renderChild: function (child, i) {
        return React.addons.cloneWithProps(child, {
            // use the prop, not state
            active: this.props.active === i,
            key: i,

            // let the parent decide how to handle the data change
            // give it the clicked index
            onSelect: this.props.onSelect.bind(null, i)
        });
    }
});
var NavItem = React.createClass({
    propTypes: {
        // it's a boolean
        active:     React.PropTypes.bool,
        onSelect:   React.PropTypes.func
    },
    // again, no state
    //getInitialState: function () {},

    render: function () {
        // just pass the onSelect handler in directly
        // let the parent handle it
        return this.transferPropsTo(
            <a className={this.props.active ? 'active' : ''} 
               onClick={this.props.onSelect}>
                {this.props.label}
            </a>
        );
    }
});
var App = React.createClass({
    getInitialState: function(){ return {active: 0} },

    handleSelect: function(i){ this.setState({active: i}) },

    render: function () {
        return (
            <Nav onSelect={this.handleSelect} active={this.state.active}>
                <NavItem label="Home" />
                <NavItem label="Page1" />
                <NavItem label="Page2" />
            </Nav>
        );
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM