我的组件数据是根据输入的路由-/reports/:id
即/reports/1
/reports/
检索match.params.id
之后的“ 1”,然后我对以下网址进行调度调用:
fetchDashData(`http://ee-etap.devops.fds.com/api/etap/v1/templates/template/report/${match.params.id}`)
当用户输入无效ID时,即/reports/a
-我想将用户重定向回/reports
,后者会显示登录页面和错误消息,例如:
return <Redirect to={{
pathname: '/reports',
state: { templateId: match.params.id } }}
/>;
一切正常,直到用户尝试访问有效的“ id”,即错误的{-{1}}之后的/reports/1
,其中用户立即重定向回{{ 1}}页面,因为获取调用是异步的,尚未完成为/reports/a
加载数据。
我已经定义了isLoading状态。但是如何防止这种情况发生?
ReportsDashboard.jsx (/reports
)
/reports/1
BrowseReport.jsx (/reports/:id
)
class ChartsDashboard extends React.Component {
componentDidMount() {
const { fetchDashData, data, isLoading, hasErrored, match } = this.props;
if ( match.params && match.params.id ) {
fetchDashData(`http://ee-etap.devops.fds.com/api/etap/v1/templates/template/report/${match.params.id}`);
}
}
render() {
const { data, hasErrored, isLoading, classes, match } = this.props;
if ( isLoading ) {
return (
<div style={{ margin: '0 auto', textAlign: 'center' }}>
<CircularProgress size={50} color="secondary" />
</div>
);
}
if ( data && data !== null ) {
const { TemplateReport } = data;
const {
errorBarChart, historyTriggers, historyLineChart, jobs, lastBuildDonutChart, features,
} = TemplateReport;
if (errorBarChart.length === 0) {
// error in data
return <Redirect to={{
pathname: '/reports',
state: { templateId: match.params.id } }}
/>;
}
const keys = [];
errorBarChart.forEach((errorItem) => {
Object.keys(errorItem).forEach((errorKey) => {
if (errorKey !== 'category') {
keys.push(errorKey);
}
});
});
if (match.params.id) {
return (
<div className="page-container">
<Grid container spacing={24}>
<Grid item xs={12} lg={4}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Error By Categories</h4>
<div style={{ height: '350px' }}>
<ResponsiveBar
data={errorBarChart}
keys={keys}
indexBy="category"
margin={{
top: 50,
right: 50,
bottom: 50,
left: 50,
}}
padding={0.1}
colors="paired"
colorBy="id"
axisBottom={{
orient: 'bottom',
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'CATEGORY',
legendPosition: 'middle',
legendOffset: 36,
}}
axisLeft={{
orient: 'left',
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'ERROR COUNT',
legendPosition: 'middle',
legendOffset: -40,
}}
labelSkipWidth={12}
labelSkipHeight={12}
labelTextColor="inherit:darker(1.6)"
animate
motionStiffness={90}
motionDamping={15}
/>
</div>
</Paper>
</Grid>
<Grid item xs={12} lg={4}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Pass Rate %</h4>
<div style={{ height: '350px' }}>
<ResponsivePie
colors="paired"
colorBy={this.pieColors}
margin={{
top: 40,
right: 40,
bottom: 40,
left: 40,
}}
data={lastBuildDonutChart}
animate
defs={[
linearGradientDef('gradientRed', [{ offset: 0, color: 'red' }, { offset: 100, color: '#ffcdd2', opacity: 0.3 }]),
linearGradientDef('gradientYellow', [{ offset: 0, color: 'yellow' }, { offset: 100, color: '#f7bf18a3', opacity: 0.3 }]),
linearGradientDef('gradientGreen', [{ offset: 0, color: '#38da3e' }, { offset: 100, color: '#38da3e', opacity: 0.3 }]),
]}
fill={[
{ match: { id: 'Fail' }, id: 'gradientRed' },
{ match: { id: 'Pass' }, id: 'gradientGreen' },
{ match: { id: 'Undefined' }, id: 'gradientYellow' },
]}
radialLabelsSkipAngle={10}
radialLabelsTextXOffset={6}
radialLabelsTextColor="#333333"
radialLabelsLinkOffset={0}
radialLabelsLinkDiagonalLength={8}
radialLabelsLinkHorizontalLength={7}
radialLabelsLinkStrokeWidth={1}
radialLabelsLinkColor="inherit"
innerRadius={0.5}
padAngle={0.7}
cornerRadius={3}
/>
</div>
</Paper>
</Grid>
<Grid item xs={12} lg={4}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Jobs Triggered</h4>
<JobsTable data={jobs} templateId={match.params.id} />
</Paper>
</Grid>
<Grid item xs={12} lg={12}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Scenarios Table</h4>
<Tooltip title="Scenario Report">
<a href={`/reports/${match.params.id}/scenarioHistory`} rel="noopener noreferrer">
<IconButton aria-label="Scenario Report">
<AssignmentIcon />
</IconButton>
</a>
</Tooltip>
<ScenariosTable data={features} />
</Paper>
</Grid>
<Grid item xs={12} lg={12}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Execution History</h4>
<div style={{ height: '400px' }}>
<ResponsiveLine
colors="paired"
colorBy="id"
margin={{
top: 20,
right: 20,
bottom: 60,
left: 80,
}}
data={historyLineChart}
enableArea={true}
animate
yScale={{ type: 'linear', stacked: true }}
/>
</div>
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
<h4 className={classes.heading}>Previous Builds</h4>
<PreviousBuildsTable data={historyTriggers} templateId={match.params.id}/>
</Paper>
</Grid>
</Grid>
</div>
);
}
}
// error in data
return <Redirect to={{
pathname: '/reports',
state: { templateId: match.params.id } }}
/>;
}
}
const mapStateToProps = state => ({
data: state.reports.data,
hasErrored: state.reports.hasErrored,
isLoading: state.reports.isLoading,
});
const mapDispatchToProps = dispatch => ({
fetchDashData: url => dispatch(chartDataFetch(url)),
});
export default compose(
withStyles(styles),
withRouter,
connect(
mapStateToProps,
mapDispatchToProps,
),
)(ChartsDashboard);
actions.jsx
/reports/
reducers.jsx
class BrowseReports extends React.Component {
constructor(props) {
super(props);
this.state = {
searchVal: '',
errorMsg: '',
}
this.onSearchChange = this.onSearchChange.bind(this);
this.goToTemplateReport = this.goToTemplateReport.bind(this);
}
componentDidMount() {
if (this.props.location && this.props.location.state && this.props.location.state.templateId) {
this.state.errorMsg = `Template Name "${this.props.location.state.templateId}" does not exist, please try again`;
this.props.history.replace('/reports', null);
}
}
onSearchChange(val) {
this.setState({ searchVal: val });
}
goToTemplateReport(val) {
this.props.history.push(`/reports/${val}`);
}
render() {
const { classes, location } = this.props;
const { searchVal, errorMsg } = this.state;
return (
<div className="page-container" style={{ textAlign: 'center' }}>
<Grid container justify="center" spacing={24}>
<Grid item xs={12} lg={8}>
{/* dashData Error */}
<h4 className={classes.errorMsg}>
{/* ERROR MESSAGE HERE */}
{errorMsg}
</h4>
<SearchBar
value={this.state.searchVal}
placeholder='Search for Template Name'
onChange={(value) => this.onSearchChange(value)}
onRequestSearch={(value) => this.goToTemplateReport(value)}
style={{
margin: '0 auto',
}}
/>
</Grid>
<Grid item xs={12} lg={6}>
<Paper className={classes.paper}>
<CompletedJobsTable></CompletedJobsTable>
</Paper>
</Grid>
<Grid item xs={12} lg={6}>
<Paper className={classes.paper}>
<ActiveJobsTable></ActiveJobsTable>
</Paper>
</Grid>
</Grid>
</div>
)
}
}
export default compose(
withStyles(styles),
withRouter
)(BrowseReports);
答案 0 :(得分:1)
您需要将templateId保存为全局状态(在加载数据时进行设置)。仅当路径中的templateId等于全局状态中的templateId时,才需要显示组件数据。