【发布时间】:2016-09-14 21:29:35
【问题描述】:
我遇到了一个问题,我有多个嵌套路由来制作选项卡式组件,理想情况下,单击选项卡会更改 url,留在页面上并将组件呈现为子级。这工作得很好。
使用 url 路由作为选项卡的原因是,如果用户在应用程序的其他位置单击 sales/:id/notes,它将直接转到正确的选项卡。
问题是我正在从父路由中的componentDidMount 函数中获取所有数据。因此,当SalesShowPage 挂载时,它会发出请求。如果我直接转到SalesShowPage,然后单击NotesTab,则所有数据都已完美加载,因为它在加载时发出了请求。
如果我们直接转到sales/:id/notes,就会出现问题,因为NotesTab 是一个子组件,如果我尝试在状态中设置isFetching 标志,则render 和componentDidMountmethods 在SalesShowPage 之前被调用直到 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)));
};
}
【问题讨论】:
标签: reactjs react-router react-redux