Это сводит меня с ума. Когда я пытаюсь использовать React Router Link во вложенном маршруте, ссылка обновляется в браузере, но вид не меняется. Однако, если я обновляю страницу до ссылки, она делает это. Так или иначе, компонент не обновляется, когда он должен (или, по крайней мере, что цель).
Вот как выглядят мои ссылки (prev/next-item - действительно vars):
<Link to={'/portfolio/previous-item'}>
<button className="button button-xs">Previous</button>
</Link>
<Link to={'/portfolio/next-item'}>
<button className="button button-xs">Next</button>
</Link>
Хакерное решение заключается в том, чтобы manaully вызвать forceUpate() как:
<Link onClick={this.forceUpdate} to={'/portfolio/next-item'}>
<button className="button button-xs">Next</button>
</Link>
Это работает, но вызывает полное обновление страницы, которое мне не нужно, и ошибка:
ReactComponent.js:85 Uncaught TypeError: Cannot read property 'enqueueForceUpdate' of undefined
Я искал высоко и низко для ответа, и ближе всего я мог прийти: https://github.com/reactjs/react-router/issues/880. Но он старый, и я не использую чистую визуализацию mixin.
Вот мои соответствующие маршруты:
<Route component={App}>
<Route path='/' component={Home}>
<Route path="/index:hashRoute" component={Home} />
</Route>
<Route path="/portfolio" component={PortfolioDetail} >
<Route path="/portfolio/:slug" component={PortfolioItemDetail} />
</Route>
<Route path="*" component={NoMatch} />
</Route>
По какой-то причине вызов Link не приводит к пересоединению компонента, который должен произойти, чтобы получить контент для нового представления. Он вызывает компонент componentDidUpdate, и я уверен, что могу проверить изменение слияния URL-адресов, а затем запустить мой аймакс-вызов/просмотр там, но похоже, что это не нужно.
EDIT (больше соответствующего кода):
PortfolioDetail.js
import React, {Component} from 'react';
import { browserHistory } from 'react-router'
import {connect} from 'react-redux';
import Loader from '../components/common/loader';
import PortfolioItemDetail from '../components/portfolio-detail/portfolioItemDetail';
import * as portfolioActions from '../actions/portfolio';
export default class PortfolioDetail extends Component {
static readyOnActions(dispatch, params) {
// this action fires when rendering on the server then again with each componentDidMount.
// but not firing with Link...
return Promise.all([
dispatch(portfolioActions.fetchPortfolioDetailIfNeeded(params.slug))
]);
}
componentDidMount() {
// react-router Link is not causing this event to fire
const {dispatch, params} = this.props;
PortfolioDetail.readyOnActions(dispatch, params);
}
componentWillUnmount() {
// react-router Link is not causing this event to fire
this.props.dispatch(portfolioActions.resetPortfolioDetail());
}
renderPortfolioItemDetail(browserHistory) {
const {DetailReadyState, item} = this.props.portfolio;
if (DetailReadyState === 'WORK_DETAIL_FETCHING') {
return <Loader />;
} else if (DetailReadyState === 'WORK_DETAIL_FETCHED') {
return <PortfolioItemDetail />; // used to have this as this.props.children when the route was nested
} else if (DetailReadyState === 'WORK_DETAIL_FETCH_FAILED') {
browserHistory.push('/not-found');
}
}
render() {
return (
<div id="interior-page">
{this.renderPortfolioItemDetail(browserHistory)}
</div>
);
}
}
function mapStateToProps(state) {
return {
portfolio: state.portfolio
};
}
function mapDispatchToProps(dispatch) {
return {
dispatch: dispatch
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PortfolioDetail);
PortfolioItemDetail.js
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Gallery from './gallery';
export default class PortfolioItemDetail extends React.Component {
makeGallery(gallery) {
if (gallery) {
return gallery
.split('|')
.map((image, i) => {
return <li key={i}><img src={'/images/portfolio/' + image} alt="" /></li>
})
}
}
render() {
const { item } = this.props.portfolio;
return (
<div className="portfolio-detail container-fluid">
<Gallery
makeGallery={this.makeGallery.bind(this)}
item={item}
/>
</div>
);
}
}
function mapStateToProps(state) {
return {
portfolio: state.portfolio
};
}
export default connect(mapStateToProps)(PortfolioItemDetail);
gallery.js
import React, { Component } from 'react';
import { Link } from 'react-router';
const Gallery = (props) => {
const {gallery, prev, next} = props.item;
const prevButton = prev ? <Link to={'/portfolio/' + prev}><button className="button button-xs">Previous</button></Link> : '';
const nextButton = next ? <Link to={'/portfolio/' + next}><button className="button button-xs">Next</button></Link> : '';
return (
<div>
<ul className="gallery">
{props.makeGallery(gallery)}
</ul>
<div className="next-prev-btns">
{prevButton}
{nextButton}
</div>
</div>
);
};
export default Gallery;
Новые маршруты, основанные на предположении Anoop:
<Route component={App}>
<Route path='/' component={Home}>
<Route path="/index:hashRoute" component={Home} />
</Route>
<Route path="/portfolio/:slug" component={PortfolioDetail} />
<Route path="*" component={NoMatch} />
</Route>