使用React路由器扩展组件

时间:2016-10-10 09:54:21

标签: reactjs react-router

假设我有一个带有一些React Router导航的Foo组件:

var Foo = React.createClass({
    render: function() {
        return (<div>
            <Link to="/foo/1">1</Link>;
            <Link to="/foo/2">2</Link>;
            {this.props.children}
        </div>);
    }
});
var Foo1 = React.createClass({
    render: function() {
        return <p>foo 1</p>;
    }
});
var Foo2 = React.createClass({
    render: function() {
        return <p>foo 2</p>;
    }
});
ReactDOM.render((
    <Router>
        <Route path="/" ...>
            <Route path="foo" component={Foo}>
                <Route path="1" component={Foo1} />
                <Route path="2" component={Foo2} />
            </Route>
        </Route>
    </Router>
), document.getElementById('main'));

现在让我说我也有一个Bar组件,它非常相似(除了bar而不是foo)。在“经典”的React应用程序中,我会“提取”常用逻辑,如下所示:

var Element = React.createClass({
    render: function() {
        return (<div>
            <Link to={this.props.url + '/1'}>1</Link>;
            <Link to={this.props.url + '/2'}>2</Link>;
            {this.props.children && React.cloneElement(this.props.children {
                name: this.props.name // Ugly hack to propagate props...
            })}
        </div>);
    }
});
var Element1 = React.createClass({
    render: function() {
        return <p>{this.props.name} 1</p>;
    }
});
var Element2 = React.createClass({
    render: function() {
        return <p>{this.props.name} 2</p>;
    }
});
var Foo = React.createClass({
    render: function() {
        return <Element url="/foo" name="foo" />;
    }
});
var Bar = React.createClass({
    render: function() {
        return <Element url="/bar" name="bar" />;
    }
});

正如你所看到的,我已经差不多得到了它(即使是丑陋的道具传播黑客......)。我缺少的部分是如何定义路由本身:

ReactDOM.render((
    <Router>
        <Route path="/" ...>
            <Route path="foo" component={Foo}>
                <Route path="1" component={?} />
                <Route path="2" component={?} />
            </Route>
        </Route>
    </Router>
), document.getElementById('main'));

我的意思是,不再有Foo1Foo2个组件,因为Foo有一个Element,它们通常来自这些组件。当然,我可以明确定义Foo1以使Element1Foo2拥有Element2,但之后我必须实施Foo而不是让Element为我做;或者我可以将组件本身作为道具传递(即Foo = ... <Element ... component1={Foo1} component2={Foo2} /> ......但是接着是什么?)。

那么:如何通过React Router实现这种React-ious“继承通过组合”?或者还有另一种方法吗?

1 个答案:

答案 0 :(得分:0)

我想到了一个解决方案,所以我想我会把它发布给有类似问题的人。请注意我还是新手......呃......&#34;心态&#34;,所以它可能不是最好的方式。

这就是事情:foo / bar差异(url="/foo|/bar"name="foo|bar")可以&#34;总结&#34;转换为单个"foo|bar"标记,然后可以将其作为参数提取到网址中。那就是:

ReactDOM.render((
    <Router>
        <Route path="/" ...>
            <Route path="/:tag" component={Element}>
                <Route path="/:tag/1" component={Element1} />
                <Route path="/:tag/2" component={Element2} />
            </Route>
        </Route>
    </Router>
), document.getElementById('main'));

可以重写元素以将该标记考虑在内:

var Element = React.createClass({
    render: function() {
        return (<div>
            <Link to={'/' + this.props.params.tag + '/1'}>1</Link>;
            <Link to={'/' + this.props.params.tag + '/2'}>2</Link>;
            {this.props.children}
        </div>);
    }
});
var Element1 = React.createClass({
    render: function() {
        return <p>{this.props.params.tag} 1</p>;
    }
});
var Element2 = React.createClass({
    render: function() {
        return <p>{this.props.params.tag} 2</p>;
    }
});

那就是它!您甚至不需要<Foo /><Bar />组件。

我对这个解决方案并不完全满意的原因是它适用于一个足够简单的案例(比如这个例子,或者我正在研究的实际CMS),但我不是确定它可以扩展到更复杂的设计;并且存在网址冲突:首先必须显示带有/baz组件的<Baz />路由,否则将评估带有<Element />标记的"baz" 。我仍然没有找到如何使用React Router定义复杂参数(如正则表达式),但如果我这样做,我将更新答案。