在获取数据之前,React-Router选项卡安装

时间:2016-09-14 21:29:35

标签: reactjs react-router react-redux

我遇到过一个问题,我有多个嵌套路由来制作选项卡式组件,理想情况下单击选项卡将更改网址,保留在页面上并将组件渲染为子级。这很好用。

将网址路由用作标签的原因是,如果应用中的其他位置用户点击sales/:id/notes,则会直接转到正确的标签。

问题是我从父路由中的componentDidMount函数获取所有数据。因此,当SalesShowPage安装时,它会发出请求。如果我直接转到SalesShowPage,然后点击NotesTab,则所有数据都会完全加载,因为它会在加载时发出请求。

如果我们直接转到sales/:id/notes,问题就会发生,因为NotesTab是一个子组件,rendercomponentDidMount方法会在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)));
  };
}

1 个答案:

答案 0 :(得分:1)

您在组件安装后即可获取,这意味着它会在您仍然获取该数据时呈现您需要获取数据的标签。我建议采取双管齐下的方法:

首先,在componentWillMount()中开始挂载之前获取数据:

componentWillMount () {
  this.props.fetchSales(this.props.saleId);
}

但是因为它是一个异步动作,它仍然不太可能及时完成,所以你需要一个后备:

SalesShowPage.defaultProps = {
  showTabs: false
};

然后,如果TabsshowTabs,您可以呈现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来显示加载屏幕。