0

My use case is this: I have a component that I want to control the url. It will have 3 "selects" in it - one for selecting a customer, one for selecting a courier, and one for selecting a service. It should (a) react to the route correctly by rendering the correct one of those three options IF provided, (b) render even if those parameters aren't there, and (c) change the route appropriately when an option is clicked

Here's my base App.js which illustrates the containing route and how I'm expecting the url to look:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import autoBind from 'react-autobind';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { BrowserRouter, Route, NavLink } from "react-router-dom";
import CcsSelect from './customer-prices/ccs-select';

class App extends Component {
    constructor(props) {
        super(props);

        this.state = {
            customers: window._customers_json || [],
            couriers: window._couriers_json || [],
            services: window._services_json || []
        };

        autoBind(this);
    }

    render() {
        return (
            <>
                <ToastContainer />
                <BrowserRouter basename="/app/customer-prices">
                    <Route exact={false} path="/:customerid/:courierid/:serviceid">
                        <CcsSelect/>
                    </Route>

                    <h1>I'm in react! Hi Mom</h1>
                </BrowserRouter>
            </>
        )
    }
}


const $container = document.getElementById('react-container');
if ($container) {
    ReactDOM.render(<App />, $container);
}

And here's my ccs-select.jsx file, which I'm expecting to render inside the Route EVEN IF there are no parameters:

import React, { Component } from 'react';
import { BrowserRouter, Route, withRouter } from "react-router-dom";
import autoBind from 'react-autobind';

class CcsSelect extends Component {
    constructor(props) {
        super(props);

        console.log(props);

        this.state = {
            customer: props.match.params.customerid,
            courier: props.match.params.courierid,
            service: props.match.params.serviceid
        };

        autoBind(this);
    }

    render() {
        return (
            <div>
                <p>I'm in the router</p>
                <p>customer id: {this.state.customer}</p>
                <p>courier id: {this.state.courier}</p>
                <p>service id: {this.state.service}</p>
            </div>

        )
    }
}

export default withRouter(CcsSelect);

Now at the moment obviously CssSelect doesn't change the path - I'm not dealing with that yet. It appropriately renders when I set the path to, say, /app/customer-prices/x/y/z, including setting the state variables and rendering the x, y, z strings. But it's not rendering when I use the url /app/customer-prices/ -- whereas what I'm wanting is for it to render and have the state representing each url parameter to be null if it's not supplied.

What's the best way to get what I'm looking for?

TKoL
  • 13,158
  • 3
  • 39
  • 73
  • One idea I had was instead to change the Route path to '/' and then, in my CcsSelect class just use a `.split()` function on the url path to get the separate parts. I don't like it as much but that's at least acceptable. – TKoL Oct 15 '19 at 11:52

1 Answers1

0

Currently, you only have one route with the path /:customerid/:courierid/:serviceid.

You have to create a new route with the path / and the exact param set to true to handle the url /app/customer-prices/. In this route, you can have the same children as the other route, it's not a problem.

Here an example :

<BrowserRouter basename="/app/customer-prices">
  <Route exact={false} path="/:customerid/:courierid/:serviceid">
    <CcsSelect/>
  </Route>
  <Route exact path="/">
    <CcsSelectOrAnotherComponent/>
  </Route>

  <h1>I'm in react! Hi Mom</h1>
</BrowserRouter>
Darkilen
  • 571
  • 4
  • 18
  • But the first CcsSelect will still only render when all three url variables are present, and the second one will render WITHOUT the param props filled out as I'm expecting. – TKoL Oct 15 '19 at 14:47
  • You want to match `/`, `/:customerId/`, ..., `/:customerid/:courierid/:serviceid` with a single route ? – Darkilen Oct 15 '19 at 14:50
  • Yes. I tried to explain my use case well enough that if using something other than a route is ideal, or I need to rethink it entirely, then hopefully you can understand what I'm trying to achieve. – TKoL Oct 15 '19 at 14:53
  • If the url passed is `/x`, I want `this.props.match, customerId` to be `x` and the other variables to be null, if you get what I mean here. – TKoL Oct 15 '19 at 14:54
  • 2
    I think this is what you want : optional path parameters https://stackoverflow.com/a/35604855/9150452 – Darkilen Oct 16 '19 at 08:22
  • thank you! I'm going to try that out some time this week. – TKoL Oct 16 '19 at 16:52