React.js - 如何创建 Accordeon(与兄弟姐妹交谈)

React.js - how to create Accordeon (talking to siblings)

我刚开始使用 react.js,我喜欢组件的工作方式。我创建了一个 Card 组件,它会在点击时添加一个 css-class expanded。这就像一个魅力。现在我希望所有其他卡片在单击另一张卡片后松开 expanded 属性。在 jQuery 中,我将使用 siblings 来执行此操作。

react.js 的正确解决方案是什么?

这是我的代码:

var Card = React.createClass({

    getInitialState: function () {
        return {
            expanded: false,
            //clickCount: 0
        };
    },

    handleClick: function (event) {
        this.setProps({expanded: !this.props.expanded});
    },

    render: function () {
        var cx = React.addons.classSet;
        var classes = cx({
            'card': true,
            'expanded': this.state.expanded
        });

        return (
            <li className={classes} onClick={this.handleClick}>
                <h1>{this.props.name}</h1>
                <h2>{this.props.entf.toFixed(2)} km</h2>
            </li>
        )
    }

});


var App = React.createClass({

    handleClick: function (event) {
        console.log("clicked");
    },

    render: function () {

        var pools = this.props.data.map(function (pool) {
            return (
                <Card onClick={this.handleClick} name={pool.name} entf={pool.entf} />
            );
        });

        return (<ul>
                {pools}
        </ul>
        )
    }
});

而不是使用 siblings,您应该在 App 组件的 state 中保留扩展卡片的标识符,并在所选卡片发生变化时让 React 重新渲染。

这是一个如何使用 React 来实现的示例:

JSfiddle:http://jsfiddle.net/vdw27xpf/

var Card = React.createClass({

    render: function () {
        var cx = React.addons.classSet;
        var classes = cx({
            'card': true,
            'expanded': this.props.expanded
        });

        return (
            <li className={classes} onClick={this.props.onClick}>
                <h1>{this.props.name}</h1>
                <h2>{this.props.entf.toFixed(2)} km</h2>
            </li>
        )
    }

});


var App = React.createClass({

    getInitialState : function(){
        return { expandedCardName : null };
    },

    handleClick: function (value) {
       this.setState({ expandedCardName : value });
    },

    render: function () {

        var pools = this.props.data.map(function (pool) {
            return (
                <Card key={pool.name}
                      expanded = { pool.name == this.state.expandedCardName }
                      onClick={this.handleClick.bind(this,pool.name)} 
                      name={pool.name} entf={pool.entf} />
            );
        }.bind(this));

        return (<ul>
                {pools}
            </ul>
        )
    }
});
var data = [ { name:"card1", entf:60 },{ name:"card2", entf:50 } ]; 
React.render(<App data={data} />, document.body);

React 是不是超级棒?

为了在不进行过多修改的情况下获得您想要的行为,我建议将回调 onClickonExpand 传递给每个 <Card/>。激活 Card 后,它会运行可以在 App 状态中设置变量(可能 activeCard)的回调。在 App 的 render 方法中,修改 map 函数,为每张 Card 提供一个 expanded 布尔值,这取决于卡片的 name/id 是否匹配 activeCard。在每张卡片的逻辑中使用新的 expanded 道具而不是 this.state.expanded

var Card = React.createClass({

render: function () {
    var cx = React.addons.classSet;
    var classes = cx({
        'card': true,
        'expanded': this.props.expanded
    });

    return (
        <li className={classes} onClick={this.props.onClick}>
            <h1>{this.props.name}</h1>
            <h2>{this.props.entf.toFixed(2)} km</h2>
        </li>
    )
}

});


var App = React.createClass({

getInitialState: function () {
    return { activeCard: '' }
},

render: function () {

    var pools = this.props.data.map(function (pool) {
        return (
            <Card onClick={this.handleClick.bind(this,pool.name)} name={pool.name} entf={pool.entf} expanded={pool.name == this.state.activeCard} />
        );
    }.bind(this));

    return (<ul>
            {pools}
    </ul>
    )
},

handleClick: function (value) {
    this.setState({ activeCard: value })
}
});

在 React 中工作时,请考虑如何使组件尽可能无状态。在像 jQuery 这样的范例中,这些部分通常会自行管理,但如果您想利用 React 的潜力,请始终留意如何 'trickle' 关闭状态。