如何使用 React Router 4 单击按钮并导航到具有 URL 参数的新路由
How to click a button and navigate to a new route with URL params using React Router 4
我正在使用 React 在 Meteor 中构建一个简单的应用程序,我正在使用 React Router 4。
有一个创建新地图的按钮,当服务器 returns 新地图的 id 时,浏览器应该导航到显示新创建地图的页面。
我几乎可以正常工作了,但是当我单击按钮时,地址栏中的 URL 发生了变化,但地图组件没有呈现。刷新页面没有帮助。但如果我在地图列表中单击新地图的 link,它会正常工作。
这段代码很丑陋,我敢肯定这不是最好的方法,但它确实是我能够让它工作的唯一方法。我已经阅读了我能找到的所有论坛帖子和文档,但对我来说没有什么是清楚的。
如有任何帮助,我将不胜感激。
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} );
匹配定义的路由。
我已经更正了代码,它现在可以工作了,但我仍然觉得这不是最好的解决方案...
在我的原始代码中发现一个拼写错误(路径应该是“/map/”的“/maps/”)后,我发现了另一个 'gotcha',它是这样的:
如果路由需要 URL 参数,但未提供,则路由似乎根本不会呈现。我的路线定义为:
```JSX
<Route path="/map/:_id" render={({ match }) => (
<Map
params={match.params}
/>
)} />
如果您尝试导航到“http://localhost:3000/map/' then the component doesn't render. If you put any value on the end e.g. '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));
我正在使用 React 在 Meteor 中构建一个简单的应用程序,我正在使用 React Router 4。
有一个创建新地图的按钮,当服务器 returns 新地图的 id 时,浏览器应该导航到显示新创建地图的页面。
我几乎可以正常工作了,但是当我单击按钮时,地址栏中的 URL 发生了变化,但地图组件没有呈现。刷新页面没有帮助。但如果我在地图列表中单击新地图的 link,它会正常工作。
这段代码很丑陋,我敢肯定这不是最好的方法,但它确实是我能够让它工作的唯一方法。我已经阅读了我能找到的所有论坛帖子和文档,但对我来说没有什么是清楚的。
如有任何帮助,我将不胜感激。
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} );
匹配定义的路由。
我已经更正了代码,它现在可以工作了,但我仍然觉得这不是最好的解决方案...
在我的原始代码中发现一个拼写错误(路径应该是“/map/”的“/maps/”)后,我发现了另一个 'gotcha',它是这样的:
如果路由需要 URL 参数,但未提供,则路由似乎根本不会呈现。我的路线定义为:
```JSX
<Route path="/map/:_id" render={({ match }) => (
<Map
params={match.params}
/>
)} />
如果您尝试导航到“http://localhost:3000/map/' then the component doesn't render. If you put any value on the end e.g. '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));