我遇到了一個問題,我有多個嵌套的路由,使標籤組件理想地點擊選項卡將更改URL,留在頁面上並呈現組件作爲子組件。這工作得很好。React-Router選項卡組件數據提取之前的組件安裝
將url路徑作爲製表符使用的原因是,如果應用程序中的某個用戶單擊了sales/:id/notes
,它將直接轉到正確的製表符。
問題是我從父路由中的componentDidMount
函數中獲取所有數據。所以當SalesShowPage
掛載它發出請求。如果我直接轉到SalesShowPage
,然後點擊NotesTab
,所有數據都會在載入請求時完美加載。
問題發生,如果我們直接去sales/:id/notes
,因爲NotesTab
是一個子組件的render
和componentDidMount
方法被SalesShowPage
之前調用,如果我嘗試設置isFetching
標誌狀態時,它不會被調用後才NotesTab
已安裝,因爲它從父組件發出請求操作。
在循環所有音符時,這會爲音符引發未定義的錯誤。
有沒有一種更好的方法來處理從具有react-router的嵌套路由的父節點獲取數據?
當數據實際從父級獲取時,能否延遲路由組件的渲染或顯示加載消息?我不想從componentWillMount
任意設置isFetching標誌,然後數據提取並顯示一個假加載圖標。
我可以在組件掛載時提出請求,但需要更改端點並添加其他路由。而不是使用當前的終點。
下面的代碼是一個簡化版本,以便於理解。
// 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
標誌設置爲真作品的服務器的一個副本。但是在我們指定的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)));
};
}