我遇到过一个问题,我有多个嵌套路由来制作选项卡式组件,理想情况下单击选项卡将更改网址,保留在页面上并将组件渲染为子级。这很好用。
将网址路由用作标签的原因是,如果应用中的其他位置用户点击sales/:id/notes
,则会直接转到正确的标签。
问题是我从父路由中的componentDidMount
函数获取所有数据。因此,当SalesShowPage
安装时,它会发出请求。如果我直接转到SalesShowPage
,然后点击NotesTab
,则所有数据都会完全加载,因为它会在加载时发出请求。
如果我们直接转到sales/:id/notes
,问题就会发生,因为NotesTab
是一个子组件,render
和componentDidMount
方法会在SalesShowPage
之前被调用尝试设置一个isFetching
标志,直到NotesTab
挂载后它才会被调用,因为它从父组件发出请求动作。
当循环遍历所有音符时,这将为音符抛出未定义的错误。
有没有更好的方法来处理使用react-router从嵌套路由的父级获取数据?
当实际从父级获取数据时,是否可以延迟路由组件的呈现或显示加载消息?我不想从componentWillMount
任意设置isFetching标志,然后显示数据并显示假加载图标。
我可以在该组件安装时请求所有注释,但这需要更改API
端点并添加另一个路由。而不是使用当前的终点。
以下代码是一个简化版本,以便于理解。
// Routes.js
<Route path="/sales/:id" component={SalesShowPage} >
<Route path="contacts" component={ContactsTab}/>
<Route path="notes" component={NotesTab}/>
<Route path="emails" component={EmailsTab}/>
</Route>
下面呈现的{props.children}
是上述路线中的组件。
//Tabs.js
const Tabs = (props) => {
return (
<div className='tabsContainer'>
<TabsHeader>
<Link to='sales/:id/contacts'>Contacts</Link>
<Link to='sales/:id/notes'>Notes</Link>
<Link to='sales/:id/emails'>Emails</Link>
</TabsHeader>
<TabsContent className='tabContent'>
{props.children}
</TabsContent>
</div>
);
};
这是渲染的主要组件,并为所有选项卡提取数据。并非所有选项卡都在此组件上提取数据,因此某些选项卡会自行提出数据请求。例如,由于查询大小以及查看该标签的频率,电子邮件标签不会在初始页面加载时查询所有电子邮件。
//SaleShowPage
class SalesShowPage extends React.Component {
constructor (props) {
super(props);
}
componentDidMount () {
this.props.fetchSales(this.props.saleId);
}
render () {
return (
<div className={styles.flex}>
<SalesDetails sale={this.props.sale}/>
<Tabs {...this.props}/>
</div>
);
}
}
const mapStateToProps = (state, props) => {
return {
saleId: props.params.id,
sale: state.sales[props.params.id],
};
};
const mapDispatchToProps = (dispatch) => ({
fetchSale: (id) => dispatch(fetchSale(id))
});
export default connect(mapStateToProps, mapDispatchToProps)(SalesShowPage);
以下操作是从SalesShowPage componentDidMount
方法向服务器发出的请求的副本,将isFetching
标志设置为true。但是在我们指定的Tab组件被渲染后执行会导致错误。
//SalesShowAction.js
export function fetchSale (id) {
return dispatch => {
dispatch({type: actions.FETCH_SALE_REQUEST, isFetching: true});
return API.get(`/sales/${id}`).then( json => dispatch(receiveSale(json)));
};
}
答案 0 :(得分:1)
您在组件安装后即可获取,这意味着它会在您仍然获取该数据时呈现您需要获取数据的标签。我建议采取双管齐下的方法:
首先,在componentWillMount()
中开始挂载之前获取数据:
componentWillMount () {
this.props.fetchSales(this.props.saleId);
}
但是因为它是一个异步动作,它仍然不太可能及时完成,所以你需要一个后备:
SalesShowPage.defaultProps = {
showTabs: false
};
然后,如果Tabs
为showTabs
,您可以呈现true
,您可以根据请求的成功操作设置。{/ p>
renderTabs() {
if(this.props.showTabs) {
return <Tabs {...this.props}/>;
}
}
render () {
return (
<div className={styles.flex}>
<SalesDetails sale={this.props.sale}/>
{this.renderTabs()}
</div>
);
}
如果要在标签准备就绪之前隐藏整个用户界面,可以使用isFetching
来显示加载屏幕。