Основная деталь React Router: дочерний компонент не отображает новый вид до обновления страницы
Я создаю основную навигацию точно так же, как в примере с реагирующим маршрутизатором;
У меня есть контейнерный компонент OneCheckpointContainer
, который отображает панель навигации CheckpointNav
(ссылки) и компонент данных OneCheckpointData
(этот парень извлекает данные при загрузке и рендерит OneCheckpointView
,
Когда я нажимаю одну из ссылок в CheckpointNav
ничего не происходит, кроме изменения URL в браузере. Только когда я обновляю страницу, новые данные извлекаются, и новый компонент затем отображается в дочернем представлении. (также нет ошибок)
Я не уверен, что это ошибка, потому что дочерний компонент также отвечает за выборку данных, а также представление.
Вот как у меня есть настройки маршрутов:
<Route path="/modules/:id" component={OneCheckpointContainer}>
<Route path="/modules/:id/checkpoints/:cp_id" component={OneCheckpointData} />
</Route>
OneCheckpointContainer
import React from 'react';
import CheckpointNav from './CheckpointNav';
class OneCheckpointContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
checkpoints: null,
user: null
};
}
componentWillMount() {
this.loadCheckpoints();
this.context.getUser((data) => this.setState({ user: data }));
}
loadCheckpoints() {
$.ajax({
url: `/api/v1/modules/student/${this.props.params.id}/checkpoints`,
method: 'GET',
}).done((data) => {
this.setState({ checkpoints: data });
});
}
render() {
return (
<div>
<div className="col-xs-3">
<CheckpointNav mid={this.props.params.id} checkpoints={this.state.checkpoints} />
</div>
<div className="col-xs-9">
{ this.props.children || <div>No Children Yet</div>}
</div>
</div>
)
}
}
OneCheckpointContainer.displayName = OneCheckpointContainer;
OneCheckpointContainer.contextTypes = {
getUser: React.PropTypes.func.isRequired
};
export default OneCheckpointContainer;
Вот CheckpointNav, хотя я не верю, что ошибка здесь:
import React from 'react';
import NavLink from '../widgets/NavLink';
const CheckpointNav = (props) => {
const checkpointList = props.checkpoints && props.checkpoints.length > 0 ?
props.checkpoints.map((item) => {
return <li key={item.cp._id} className="list-group-item">
<NavLink className="nav-link" to={"/modules/" + props.mid + "/checkpoints/" + item.cp._id}>
{ item.cp.title}</NavLink></li>
}) : <div>No CPS</div>;
return (
<div className="card one-module-card">
<div className="card-block modules-card-body">
<ul className="list-group tags-group">
{ checkpointList }
<li className="list-group-item new-cp"><NavLink className=""
to={'/post/checkpoint/' + props.mid}
>
New Checkpoint
</NavLink></li>
</ul>
</div>
</div>
);
};
export default CheckpointNav;
OneCheckpointData не извлекает новые данные и не отображает новые, пока я не обновлю
import React from 'react';
import CheckpointView from './CheckpointView';
class OneCheckpointData extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
checkpoint: null,
user: null
};
}
componentWillMount() {
this.loadCheckpoint();
this.context.getUser((data) => this.setState({ user: data }));
}
loadCheckpoint() {
$.ajax({
url: `/api/v1/modules/three/cp/${this.props.params.cp_id}`,
method: 'GET',
}).done((data) => {
this.setState({ checkpoint: data });
});
}
render() {
return this.state.checkpoint ? <CheckpointView user={this.state.user} checkpoint={this.state.checkpoint} /> : null;
}
}
OneCheckpointData.displayName = OneCheckpointData;
OneCheckpointData.contextTypes = {
getUser: React.PropTypes.func.isRequired
};
export default OneCheckpointData;
** Я упустил OneCheckpointView, так как он должен быть неуместным **
4 ответа
В этом случае вы можете получить реквизит в качестве параметра loadCheckpoing(props)
функция, и вы можете отправить новый реквизит на componentWillReceiveProps
как ниже
componentWillMount(this.props) {
this.loadCheckpoint(this.props);
}
componentWillReceiveProps(nextprops) {
this.loadCheckpoint(nextprops);
}
loadCheckpoint(props) {
this.context.getUser((data) => this.setState({ user: data }));
$.ajax({
url: `/api/v1/modules/three/cp/${props.params.cp_id}`, //please check i have replace the this.props to props as we have props as a parameter
method: 'GET',
}).done((data) => {
this.setState({ checkpoint: data });
});
}
Я предпочитаю использовать реагирующие-редуксные или рефлюксные библиотеки для обработки ваших запросов к данным ajax, но предложенное мной решение должно выполнить эту работу за вас.
Два шага к диагностике:
проверь ли твой метод
loadCheckpoint
вызывается каждый раз, когда вы нажимаете другую ссылку. Просто оставьте одну строку какconsole.log(new Date().toLocaleTimeString())
в этом методеесли шаг 1 успешен, то проверьте, есть ли
this
справочный вопрос в этой части:(data) => { this.setState({ checkpoint: data }); }
Кстати, вам лучше поставить вызов Ajax в componentDidMount
метод. См.: https://facebook.github.io/react/docs/component-specs.html.
Я думаю, это потому, что вы вызвали функцию loadcheckpoints в componentwillMount. Это может быть вызвано только один раз в жизненном цикле компонента. Поскольку компонент уже смонтирован, когда вы щелкнули ссылку в навигационной панели, compoenntwillmount не будет вызываться. Поэтому, выборка данных не происходит.
Я думаю, вы должны попробовать следующий подход. Функция onclick ссылок в CheckpointNav должна передаваться из OneCheckpointContainer . Загруженные данные должны быть установлены в состояние контейнера, который будет передавать данные в OneCheckpointData в качестве реквизита.
Проблема в том, что ваши компоненты извлекают данные только перед монтированием. Это работает только в первый раз, когда они отображаются. Этим компонентам также необходимо извлекать свои данные всякий раз, когда они получают новые свойства, например идентификаторы от маршрутизатора после перехода в новое местоположение.
Для этого проще всего добавить componentWillReceiveProps
который сравнивает предыдущий реквизит с новым и выбирает новые данные при необходимости.
Альтернативный способ - добавить onEnter
обработчик в вашей конфигурации маршрутов для извлечения данных при каждом изменении маршрута.
Проверьте ответы на этот вопрос, чтобы увидеть примеры обоих подходов.