Reactjs 从react更新brothers对象

Reactjs 从react更新brothers对象,reactjs,Reactjs,我正在学习react,并希望实现一个基本的导航侧栏,其中包含一些项目,我希望使我单击的最后一个激活className,而所有其他项目都不激活 在下面的代码中,我无法通过读取文档来删除resetALL with item.setState中的className,我知道它不起作用,所以我尝试使用jQuery直接操作dom。它在第一次单击时起作用,但第二次单击无效。有什么方法可以做到这一点吗?谢谢 $(document).ready(function(){ var NavIt

我正在学习react,并希望实现一个基本的导航侧栏,其中包含一些项目,我希望使我单击的最后一个激活className,而所有其他项目都不激活

在下面的代码中,我无法通过读取文档来删除resetALL with item.setState中的className,我知道它不起作用,所以我尝试使用jQuery直接操作dom。它在第一次单击时起作用,但第二次单击无效。有什么方法可以做到这一点吗?谢谢

    $(document).ready(function(){

        var NavItem = React.createClass({
            getInitialState: function() {
                return this.props.item;
            },

            handleClick: function() {
                React.render(<span>{this.props.item.description}</span>, document.getElementById('main'));

                this.props.resetALL();
                console.log("this", this);
                this.setState({active: true});
            },

            render: function() {
                var className = this.state.active ? "active" : "";
                return <li className={className}><a href="#" onClick={this.handleClick}>{this.props.item.description}</a></li>;
            }
        });

        var NavBar = React.createClass({
            items : [],

            resetALL: function() {
                this.items.forEach(function(item) {
                    console.log("item", item);
                    // item.setState({active: false});
                });

                $("#nav-sidebar li").each(function(){
                    $(this).removeClass("active");
                });
            },

            render: function() {
                var _this = this;

                this.props.items.forEach(function(item) {
                    console.log("handleClick", this.handleClick);
                    _this.items.push(<NavItem item={item} key={item.id} resetALL={_this.resetALL}/>);
                });

                return (
                    <ul className="nav nav-sidebar" id="nav-sidebar">
                        {this.items}
                    </ul>
                );
            }

        });


        var NAVLIST = [
            {id: 1, description: 'OverView', active: true},
            {id: 2, description: 'Calls'},
            {id: 3, description: 'Channels'},
            {id: 4, description: 'OverView'}
        ]

        React.render(<NavBar items = {NAVLIST} />, document.getElementById('sidebar'));


        React.render(
            <h1>Hello, FreeSWITCH!</h1>,
            document.getElementById('main')
        );

    });
当NavItem调用this.props.resetALL时,该函数未绑定到NavBar,因此无法遍历NavBar的项。您可以将其绑定到正确的范围,如下所示:

<NavItem item={item} key={item.id} resetALL={_this.resetALL.bind(this)}/>
<NavList items={NAVLIST} initialActiveItem={1} />

我在你的代码中看到了一些在react中有点不常见的东西:

每次事件发生时重新呈现主元素有点违背react.js的目的。相反,您应该通过属性和事件进行通信,并让react更新main中所需的文本 NavItem不应负责设置其活动状态,NavBar是一个更合适的位置,因为它可以容纳其他项目,并且可以轻松激活/停用所需的项目 我建议将items数组保存到state而不是成员变量中,因为任何时候想要激活另一个item,只需更新state即可 在_this.items.push中推送react组件只是一种简单的反应方式,您不需要直接存储和访问组件 直接操作react呈现的DOM元素会干扰react 另外,您不需要$document.ready 在下面,您可以找到解决问题的react.js自然方法。这里要注意三件事: 1.数据下降,事件上升 2.setState用于让react知道发生了变化 3.有一个聚合应用程序组件可帮助您更新文本

var NavBar = React.createClass({
    itemClicked: function(ev) {
        var items = this.state.items;
        var clickedId = ev.currentTarget.getAttribute("data-item-id");
        var activeItem = {};
        items.forEach(function(item) {
            if(item.id == clickedId) {
                activeItem = item;
            }
            item.active = item.id == clickedId;
        });
        //let react do the work
        this.setState({items:items});
        if(this.props.onItemChange) {
            this.props.onItemChange(activeItem);
        }
    },
    getInitialState: function() {
        return {items: this.props.items};
    },
    render: function() {
        var navItems = this.state.items.map(function(item, idx) {
            var className = item.active ? "active" : "";
            return <li key={item.id}  className={className}><a href="#" data-item-id={item.id} onClick={this.itemClicked}>{item.description}</a></li>;
        }.bind(this));

        return (
            <ul className="nav nav-sidebar" id="nav-sidebar">
                {navItems}
            </ul>
        );
    }

});

var App = React.createClass({
    handleItemChange: function(item) {
        this.setState({selectedItem: item});
    },
    getInitialState: function() {
        return {selectedItem: {description:"Hello, FreeSWITCH!"}};
    },
    render: function() {
        return (<div>
            <h1>{this.state.selectedItem.description}</h1>
            <div id="sidebar">
                <NavBar items={this.props.items} onItemChange={this.handleItemChange} />
            </div>
        </div>);
    }
});


var NAVLIST = [
    {id: 1, description: 'OverView', active: true},
    {id: 2, description: 'Calls'},
    {id: 3, description: 'Channels'},
    {id: 4, description: 'OverView'}
]

React.render(<App items = {NAVLIST} />, document.getElementById('content'));

您怀疑使用jQuery更新React管理的DOM元素上的类是对的。每当React重新呈现时,jQuery更改通常会被覆盖。为了更好地使用React,您必须对应用程序要表示的内容以及定义其状态的数据应该自然存在的位置进行大量思考和重新思考

在本例中,您试图呈现一个导航链接列表,其中只有一个链接处于活动状态。与NavItem的状态相比,导航栏是存储活动项的更合理的位置

我建议将项目列表作为道具传递给NavList,并将初始活动项目存储在NavList的状态中,或将其作为一个清晰标记的InitiallyActiviteItem传递,如下所示:

<NavItem item={item} key={item.id} resetALL={_this.resetALL.bind(this)}/>
<NavList items={NAVLIST} initialActiveItem={1} />
当需要更新活动项时,如在单击处理程序中,可以使用setState调用,如下面所示

我将在NavList上定义一个函数,该函数接受一个id并调用其setState方法将活动项设置为该id,然后将该函数作为道具传递给此行中的每个项这是NavBar实例,而item是this.props.items的一个元素:

NavItem只需知道其props.active是否为true,即可决定是否呈现活动类名,以及如何将其id传递回NavBar的updateActive函数,以便在尚未激活时使其处于活动状态。当NavBar更新时,它将重新呈现其子navitem,并且它们将被更新为正确的活动状态,以便它们可以呈现正确的类名


当然,如果单击NavItems的目的不仅仅是更新该项目是否处于活动状态,那么您必须确保该单击会触发任何其他相关操作。如果这意味着更新一个完全不同的React组件的内容,比如您在main中呈现的内容,那么请考虑将在何处存储和检索关于其他组件中应该包含的内容的状态信息。它很可能是这两个元素的父元素,或者是其他一些共享的有状态资源,比如Flux存储。有关如何推断此信息的位置的更多信息,请参阅。

谢谢,现在我明白了。ottonomy的解决方案目前对我有效。我最终会使用一个应用程序来跟踪我所想的一切。好吧,你不需要跟踪一切,但最好是:好吧,我的意思是,如果我愿意,它可以跟踪一切。正如您提到的,每次单击一个项目时,我都会重新呈现主元素,就像切换页面一样。它虽然不是react的目的,但仍然有效。但是Navbar和main元素是两个不同的元素,我必须使用window.addEventListener的sub-PubSub使它们相互对话,正如所提到的。如果在应用程序中包装所有内容,我们可以使用一些父/子回调,但我担心当子树变得太深时?哪一个是最佳实践?不必担心性能,react有很多优化功能,在一棵大树上举办的活动效果非常好