3

I've spent the last few days trying to get my nested routes to work, and I have to say that I'm completely lost.

I'm trying to get the following functionality to work:

  1. Sidebar with several links. One of them leads to /banking.
  2. /banking by default renders component { BankingCards } inside a { CardWrapper }.
  3. When user clicks on the <Link> of one of the 4 cards rendered by { BankingCards }, I want to render the nested path inside of the same { CardWrapper }.

In the code block below, you will notice I tried using a switch statement to dynamically assign a component to actionComponent. This seems to break the functionality in more ways than one.

Is it the approach that is wrong, or am I missing something about React Router components?

// Banking.js import CardWrapper from '../../Wrappers/CardWrapper/CardWrapper'; import BankingCards from './BankingCards/BankingCards'; import AddBank from './AddBank/AddBank'; import AddDebit from './AddDebit/AddDebit'; import AddCredit from './AddCredit/AddCredit'; import AddDirect from './AddDirect/AddDirect'; class Banking extends Component { state = {}; render() { const { match } = this.props; console.log(match.params); // let actionComponent; // switch (match.params.actionType) { // case 'add-bank': // actionComponent = AddBank; // break; // case 'add-debit': // actionComponent = AddDebit; // break; // case 'add-credit': // actionComponent = AddCredit; // break; // case 'add-direct': // actionComponent = AddDirect; // break; // default: // return null; // } return ( <div className={classes.Banking}> <h1 className={classes.mainHeader}>Banking</h1> <CardWrapper> <Switch> <Route exact path={`${match.path}`} component={BankingCards} /> <Route path={`${match.path}/:actionType`} component={actionComponent} /> </Switch> </CardWrapper> </div> ) } } 

and

// BankingCards.js const bankingCards = ({ match }) => { return ( <> <Card> <h1>Add Bank Account</h1> <Link to={`${match.url}/add-bank`}> <SVG src={iconPlus} className={classes.iconPlus} /> </Link> <h3>Manage accounts</h3> </Card> <Card> <h1>Add Debit Card</h1> <Link to={`${match.url}/add-debit`}> <SVG src={iconPlus} className={classes.iconPlus} /> </Link> <h3>Manage debit cards</h3> </Card> <Card> <h1>Add Credit Card</h1> <Link to={`${match.url}/add-credit`}> <SVG src={iconPlus} className={classes.iconPlus} /> </Link> <h3>Manage credit cards</h3> </Card> <Card> <h1>Add Direct Debit</h1> <Link to={`${match.url}/add-direct`}> <SVG src={iconPlus} className={classes.iconPlus} /> </Link> <h3>Manage direct debits</h3> </Card> </> ); }; 
3
  • what does print console.log(match.params); ? Commented Jan 1, 2019 at 22:33
  • An empty object. That was when I realised I wasn't doing something right. Commented Jan 1, 2019 at 22:35
  • one solution could be to use the render prop instead of component, you can do your switch case inside it Commented Jan 1, 2019 at 22:38

2 Answers 2

6

UPDATE: Found a solution after digging deeper on the website

There were 3 issues with my code:

  1. I should have used render prop instead of component for the dynamic Route.

    <Switch> <Route path={`${match.path}/:actionType`} render={props => { const actionType = props.match.params.actionType; const Component = getActionComponent(actionType); if (Component) { return <Component {...props} />; } else { return <Redirect to="/" /> } }} /> <Route path={`${match.path}`} component={BankingCards} /> </Switch> 
  2. Also, the dynamic route should have come before the /banking one. This is because the Switch statement will only render the first match. /banking was already a partial match, so the router wasn't reaching the nested routes like /banking/add-bank.

  3. The parent route, /banking, had the exact prop set to true. I now know that when using nested routes the parent route should not have exact enabled.

    class MainArea extends Component { state = {}; render() { return ( <div className={classes.MainArea}> <Route path="/banking" component={Banking} /> <Route exact path="/planner" component={Planner} /> <Route exact path="/notes" component={Notes} /> </div> ); } } 
Sign up to request clarification or add additional context in comments.

Comments

0

You can use the render function to fix your example. You have an error because in the Banking component math.params doens't have the actionType propertye.

function getActionComponent(actionType) { switch (actionType) { case 'add-bank': return AddBank; case 'add-debit': return AddDebit; case 'add-credit': return AddCredit; case 'add-direct': return AddDirect; default: return null; } <Route path={`${match.path}/:actionType`} render={props => { const actionType = props.match.params.actionType; const Component = getActionComponent(actionType); if (Component) { return <Component {...props}/>; } else { return <Redirect to="/"/> } }}/> 

3 Comments

Thanks for the suggestion, Olivier. I gave it a go, but it still doesn't work. I console logged the actionType and Component inside of the render, and still nothing comes up. And just like before, I can see that it's taking me to /banking/add-bank in the url, but the <Banking /> component isn't rendering at all. As in, not even the <h1>Banking</h1> heading is displaying. I would at least expect it to render that, but not the <CardWrapper />.
if Banking is not showing, the problem is related to the route responsible to display the Banking component, can you show us the code ?
You were right with both suggestions. I have now posted an update.