yourfavorite yourfavorite - 1 month ago 16
React JSX Question

Component structure: Swap one component based on react-router path

I'm just learning React and having a little trouble figuring out the best component structure for my app.



So this is a very rough representation of my app. Most of the page layouts will resemble this with a few exceptions.

I have 2 questions:

1) If I want to swap out "LIST OF ITEMS" for an "ADD ITEM FORM" when the user clicks the "ADD ITEM BTN" in the top right, what is the best way to structure this?

I could have one route that loads a

ListItemsPage
component and then another with an
AddItemPage
, but both of these would have a lot of redundant code (mostly other components: side bar controls, list of groups, etc). I'm assuming there is a simpler way to handle this sort of thing. Or perhaps I could do an if statement that loads either list of items or the add item form based on the current URL path.

2) What is the best strategy for redirecting to a default group? If someone goes to /group/7, then we load Group 7's List of Items. However, if someone goes to /group, I'd like to default to the first group in the list of groups so that the right side of the app is never blank.

My Routes: (open to changing these if it would make more sense)

<Route path="/" component={App}> {/* should go to /group/1 */}
<IndexRoute component={Home} />
<Route path="/group/add" component={GroupAdd} />
<Route path="/group/:id" component={GroupDetail} />
<Route path="/group/:id/item/add" component={ItemAdd} />
<Route path="/settings" component={Settings} />
</Route>

Answer

After a bit of digging over the weekend I ended up with this solution. I'm not sure if it is optimal, but it seems to be working great for me currently.

Hopefully this helps someone out there :D

Route:

<Route path="/" component={App}>
  <IndexRedirect to="/group" />
  <Route path="group" component={GroupMain}>
    <Route path="add" component={GroupAdd} />
    <Route path=":groupId" component={GroupHome} />
    <Route path=":groupId/item">
      <Route path="add" component={ItemAdd} />
    </Route>
  </Route>
</Route>

Where I want children to appear in GroupMain: (Where you see "LIST OF ITEMS" in my mockup)

{this.props.children ? React.cloneElement(this.props.children, { propsYouWantToPassToChildren }) : ''}

Then to handle the redirect to default ID, in GroupMain

componentWillReceiveProps(nextProps) {
  const { dispatch, groups, selectedGroup, params } = nextProps;
  const { groupId } = params;

  // The URL does not match the state. Update state.
  if (typeof groupId !== 'undefined' && (selectedGroup !== groupId || selectedGroup.length === 0)) {
    dispatch(selectGroup(groupId));
    return;
  }

  // No selectedGroup and No groupId in URL. Update state.
  if (typeof groupId === 'undefined' && selectedGroup.length === 0 && Object.keys(groups).length > 0) {
    const newSelectedGroup = Object.keys(groups)[0];
    dispatch(selectGroup(newSelectedGroup));
    this.context.router.push(`/group/${newSelectedGroup}`);
  }
}