如何使用React Router 4单击按钮并使用URL参数导航到新路由

时间:2018-02-23 15:35:19

标签: reactjs meteor react-router

我正在使用React在Meteor中构建一个简单的应用程序,并且我正在使用React Router 4.

有一个创建新地图的按钮,当服务器返回新地图的ID时,浏览器应该导航到显示新创建的地图的页面。

我几乎可以使用它,但是当我点击按钮时,URL会在地址栏中更改,但地图组件不会渲染。刷新页面并没有帮助。但是,如果我点击地图列表中的新地图链接,它就可以正常工作。

这段代码很丑陋,我确定它不是最好的方法,但它实际上是我能够让它完全运作的唯一方法。我已经阅读了所有可以找到的论坛帖子和文档,但对我来说并不清楚。

我非常感谢任何帮助。

Main.js

```JSX
/* global document */

import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

// Start the app with imports
import '/imports/startup/client';
import '../imports/startup/accounts-config.js';
import App from '../imports/ui/layouts/App.jsx';

Meteor.startup(() => {
    render((<BrowserRouter><App /></BrowserRouter>), document.getElementById('app'));
});

App.js:

import React, { Component } from 'react';
import { withRouter, Switch, Route, Link, Redirect } from 'react-router-dom';

import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';

// Mongodb collection
import { Maps } from '../../api/maps/maps.js';

// User Accounts
import AccountsUIWrapper from '../AccountsUIWrapper.jsx';

import Home from '../pages/home';
import Map from '../pages/map';
import About from '../pages/about';

class App extends Component {
    renderTestButton() {
        return (
            <button onClick={this.handleClick.bind(this)}>New Map</button>
        );
    }

    handleClick() {
        let that = this;
        Meteor.call('newMap', {'name': 'new map'}, function(error, result) {
            that.props.history.push(`/map/${result}`);
        });
    }

    render() {
        let newMap = this.renderNewMap();
        let testButton = this.renderTestButton();

        return (
            <div className="primary-layout">
                <header>
                    <AccountsUIWrapper />
                    {testButton}
                    <nav>
                        <ul>
                            <li><Link to='/'>Home</Link></li>
                            <li><Link to='/about'>About</Link></li>
                        </ul>
                    </nav>
                </header>

                <main>
                    <Switch>
                        <Route exact path='/' component={Home}/>
                        <Route exact path="/map/:_id" render={({ match }) => (
                            <Map
                                params={match.params}
                            />
                        )} />
                        <Route path='/about' component={About}/>
                    </Switch>

                </main>
            </div>
        );
    }
}

export default withRouter(withTracker(() => {
    const mapsHandle = Meteor.subscribe('maps');

    return {
        'maps': Maps.find({}).fetch(),
        'loading': !mapsHandle.ready(),
        'currentUser': Meteor.user(),
    };
})(App));

编辑:我的路径中有一个拼写错误,我写了that.props.history.push( / maps / $ {result} );,它应该是that.props.history.push( / map / $ {result} {{ 1}}匹配定义的路线。

我已经纠正了代码,它现在有效,但我仍然认为这不是最好的解决方案......

1 个答案:

答案 0 :(得分:1)

在我的原始代码('/ maps /',其中路径应该是'/ map /')中发现拼写错误后,我发现另一个'gotcha'就是这样:

如果路由需要URL参数,并且未提供,则路径似乎根本不呈现。我的路线定义为:

```JSX
<Route path="/map/:_id" render={({ match }) => (
<Map
params={match.params}
/>
)} />

如果您尝试导航到“http://localhost:3000/map/”,则组件不会呈现。如果你在最后加上任何价值,例如它呈现'http://localhost:3000/map/dummyvalue'。

我现在有一个更整洁的版本:

```JSX
import React, { Component } from 'react';
import { withRouter, Switch, Route, Link } from 'react-router-dom';

import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';

// Mongodb collection
import { Maps } from '../../api/maps/maps.js';

// User Accounts
import AccountsUIWrapper from '../AccountsUIWrapper.jsx';

import Home from '../pages/home';
import Map from '../pages/map';
import About from '../pages/about';

function NewMap(props) {
    function handleClick(e) {
        e.preventDefault();

        let history = props.history;
        Meteor.call('newMap', {'name': 'new map'}, (error, result) => {
            history.push(`/map/${result}`);
        });
    }

    let disabled = 'disabled';
    if (Meteor.userId()) { disabled = '';}
    return (
        <button disabled={disabled} onClick={handleClick}>New Map</button>
    );
}

class App extends Component {
    renderNewMap() {
        const history = this.props.history;
        return (
            <NewMap history={history}
            />
        );
    }

    render() {
        let newMap = this.renderNewMap();

        return (
            <div className="primary-layout">
                <header>
                    <AccountsUIWrapper />
                    {newMap}
                    <nav>
                        <ul>
                            <li><Link to='/'>Home</Link></li>
                            <li><Link to='/about'>About</Link></li>
                        </ul>
                    </nav>
                </header>

                <main>
                    <Switch>
                        <Route exact path='/' component={Home}/>
                        <Route path="/map/:_id" render={({ match }) => (
                            <Map
                                params={match.params}
                            />
                        )} />
                        <Route path='/about' component={About}/>
                    </Switch>

                </main>
            </div>
        );
    }
}

export default withRouter(withTracker(() => {
    const mapsHandle = Meteor.subscribe('maps');

    return {
        'maps': Maps.find({}).fetch(),
        'loading': !mapsHandle.ready(),
        'currentUser': Meteor.user(),
    };
})(App));