React Router master-detail:子组件在页面刷新之前不会呈现新视图
React Router master-detail: children component don't render new view until page refresh
我正在创建主从导航,就像这里的示例一样 the react router example;
我有一个容器组件 OneCheckpointContainer
,它呈现一个导航面板 CheckpointNav
(链接)和一个数据组件 OneCheckpointData
(这个人在加载时获取数据,并呈现OneCheckpointView
.
当我单击 CheckpointNav
中的一个链接时,除了浏览器中的 URL 发生变化外,没有任何反应。直到我刷新页面才获取新数据,然后在子视图中呈现一个新组件。 (也没有错误)
我不确定这个bug是不是因为子组件也负责获取数据,还有视图。
我是这样设置路由的:
<Route path="/modules/:id" component={OneCheckpointContainer}>
<Route path="/modules/:id/checkpoints/:cp_id" component={OneCheckpointData} />
</Route>
一个检查点容器
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;
一个检查点数据
不获取新数据并呈现新数据,除非我刷新
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,因为它应该是无关紧要的 **
问题是您的组件仅在挂载之前获取数据。这仅适用于第一次显示它们。这些组件还需要在收到新属性时获取数据,例如导航到新位置后来自路由器的 ID。
为了做到这一点,最简单的方法是添加一个 componentWillReceiveProps
将以前的道具与新道具进行比较,并在需要时获取新数据。
另一种方法是在路由配置中添加一个 onEnter
处理程序,以便在路由更改时获取数据。
检查 以查看这两种方法的示例。
我认为这是因为你调用了componentwillMount中的loadcheckpoints函数。这在组件生命周期中只被调用一次。
由于当您在导航栏中单击 link 时该组件已经安装,因此 compoenntwillmount 将不会是 invoked.Hence,不会发生数据提取。
我想,您应该尝试以下方法。
CheckpointNav 中 links 的 onclick 函数应该从 OneCheckpointContainer 传递。 loadeddata 应设置为容器中的 state,它将数据作为 props 传递给 OneCheckpointData。
两步诊断:
检查你的方法loadCheckpoint
是否每次点击不同的link时都被调用了。在该方法中只留下一行 console.log(new Date().toLocaleTimeString())
如果第一步成功,那么检查这部分是否有this
引用问题:
(data) => {
this.setState({ checkpoint: data });
}
顺便说一句,您最好将 ajax 调用放在 componentDidMount
方法中。参考:https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
在这种情况下,您可以获得道具作为 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 });
});
}
我更愿意使用 react-redux 或 reflux 库来处理您的 ajax 数据查询,但我建议的解决方案应该可以为您完成这项工作。
我正在创建主从导航,就像这里的示例一样 the react router example;
我有一个容器组件 OneCheckpointContainer
,它呈现一个导航面板 CheckpointNav
(链接)和一个数据组件 OneCheckpointData
(这个人在加载时获取数据,并呈现OneCheckpointView
.
当我单击 CheckpointNav
中的一个链接时,除了浏览器中的 URL 发生变化外,没有任何反应。直到我刷新页面才获取新数据,然后在子视图中呈现一个新组件。 (也没有错误)
我不确定这个bug是不是因为子组件也负责获取数据,还有视图。
我是这样设置路由的:
<Route path="/modules/:id" component={OneCheckpointContainer}>
<Route path="/modules/:id/checkpoints/:cp_id" component={OneCheckpointData} />
</Route>
一个检查点容器
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;
一个检查点数据 不获取新数据并呈现新数据,除非我刷新
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,因为它应该是无关紧要的 **
问题是您的组件仅在挂载之前获取数据。这仅适用于第一次显示它们。这些组件还需要在收到新属性时获取数据,例如导航到新位置后来自路由器的 ID。
为了做到这一点,最简单的方法是添加一个 componentWillReceiveProps
将以前的道具与新道具进行比较,并在需要时获取新数据。
另一种方法是在路由配置中添加一个 onEnter
处理程序,以便在路由更改时获取数据。
检查
我认为这是因为你调用了componentwillMount中的loadcheckpoints函数。这在组件生命周期中只被调用一次。 由于当您在导航栏中单击 link 时该组件已经安装,因此 compoenntwillmount 将不会是 invoked.Hence,不会发生数据提取。
我想,您应该尝试以下方法。 CheckpointNav 中 links 的 onclick 函数应该从 OneCheckpointContainer 传递。 loadeddata 应设置为容器中的 state,它将数据作为 props 传递给 OneCheckpointData。
两步诊断:
检查你的方法
loadCheckpoint
是否每次点击不同的link时都被调用了。在该方法中只留下一行console.log(new Date().toLocaleTimeString())
如果第一步成功,那么检查这部分是否有
this
引用问题:(data) => { this.setState({ checkpoint: data }); }
顺便说一句,您最好将 ajax 调用放在 componentDidMount
方法中。参考:https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
在这种情况下,您可以获得道具作为 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 });
});
}
我更愿意使用 react-redux 或 reflux 库来处理您的 ajax 数据查询,但我建议的解决方案应该可以为您完成这项工作。