React-router: Empty relative path does not match index

Created on 7 Nov 2016  ·  7Comments  ·  Source: ReactTraining/react-router

Not sure if this is a bug, intended behavior, or if there is a workaround. I filled out the bug report template so we could have a test case :+1:


Version

4.0.0

Test Case

http://jsbin.com/daruqi

The test case uses HashRouter to demonstrate, but the same behavior occurs when using BrowserRouter which is the router I’m targeting.

const { HashRouter, Match } = ReactRouter

ReactDOM.render((
  <HashRouter>
    <div>
      <h1>Root</h1>
      <Match pattern="/hello" render={() => (
        <div>
          <h2>Hello</h2>
          <Match pattern="" exactly render={() => (
            <h3>Index</h3>
          )}/>
         </div>
      )}/>
    </div>
  </HashRouter>
), document.getElementById('app'))

Steps to reproduce

  1. Navigate to http://output.jsbin.com/daruqi#/hello. <h3>Index</h3> does not render.
  2. Navigate to http://output.jsbin.com/daruqi#/hello/. <h3>Index</h3> does render.

Expected Behavior

That <h3>Index</h3> shows up when navigating to http://output.jsbin.com/daruqi#/hello.

Actual Behavior

The <h3>Index</h3> element only renders when navigating to http://output.jsbin.com/daruqi#/hello/.


Is this intended behavior? The relative matching feature is excellent, but I’d love to get an “index” match/route 😊

As a side note, is there a reason why a / must be omitted to define relative matches? Being able to do the following seems kind of pointless.

<Match pattern="/hello" render={() => <Match pattern="/world" component={Unreachable}/>}/>
bug

Most helpful comment

I know that relative paths in <Link>s are complicated, but that is mostly because of dot directory notation.

With patterns, those shouldn't exist, right? If a <Match> is being rendered, that means that its parent has been rendered, so a <Match pattern='../other'> could never match.

I would go so far as to say that every pattern should be relative, either to their parent <Match>'s pathname or to the root /. That determination should be made in matchPattern using the parent's pathname (and if parent doesn't exist, use /).

pattern = parent ? join(parent.pathname, pattern) : join('/', pattern)

After all, building full urls just consists of concatentating the relative pattern to the <Match>'s pathname, correct? It seems odd to require the user to always define their patterns as ${pathname}/foo

(Side note, but I did submit a PR for resolving relative locations in <Link>s and <Redirect>s. In so far as I can tell, it works correctly, but I agree that there are a lot of weird edge cases to consider. At least with RR locations only work on pathnames, so the issues with messing around with the domain don't exist.)

All 7 comments

I think that this is a bug, or at least an oversight. The workaround would be to use the pathname provided by the parent <Match>.

<Match pattern={${pathname}} />

matchPattern always matches against the full current location, so for relative patterns it joins the pattern with its parent <Match>'s matched pathname using a forward slash. It would probably make sense for the empty string pattern to just use its parent's pathname without appending a forward slash.

I don't think this is a bug. That's a relative path, and we don't really support that right now. (It's way more subtle and tricky to get to work than people think.)

I kind of regret any relative anything right now, and am inclined to remove the parent bit of matchPattern so that you know you always have to build full urls and quit "expecting" relative magic to happen :)

I know that relative paths in <Link>s are complicated, but that is mostly because of dot directory notation.

With patterns, those shouldn't exist, right? If a <Match> is being rendered, that means that its parent has been rendered, so a <Match pattern='../other'> could never match.

I would go so far as to say that every pattern should be relative, either to their parent <Match>'s pathname or to the root /. That determination should be made in matchPattern using the parent's pathname (and if parent doesn't exist, use /).

pattern = parent ? join(parent.pathname, pattern) : join('/', pattern)

After all, building full urls just consists of concatentating the relative pattern to the <Match>'s pathname, correct? It seems odd to require the user to always define their patterns as ${pathname}/foo

(Side note, but I did submit a PR for resolving relative locations in <Link>s and <Redirect>s. In so far as I can tell, it works correctly, but I agree that there are a lot of weird edge cases to consider. At least with RR locations only work on pathnames, so the issues with messing around with the domain don't exist.)

To me embracing relativity everywhere (in <Match>, in <Link>, in <Redirect> even though this would not be the default behavior of an <a> tag) would open the door for some amazingly powerful design patterns. You could compose two apps that use react-router with just a <Match>. To me, this approach feels more React-y and would make the most sense in both a non-web environment (like react-native) or a web environment.

By embracing relativity you could further write decentralized code that is highly modular, easier to throw away, and “codependent” from any other component. Intuitively, I also kind of expected this to just work, because being able to do the following doesn’t make much sense to me:

<Match pattern="/hello" render={() => (
  <Match pattern="/world" component={Unreachable}/>
)}/>

If you agree, let me know and I’ll spend some time trying to make it work. I really love what you guys have done, and I’m loving using it to build apps. This change could really help my distributed coding style :blush:

Yes, i also want relative everywhere, but I also want to ship 4.0, and I don't want relative match w/o relative link, and relative link is really tricky. All I'm saying is i'd like to remove relative stuff right now and focus on shipping a stable feature set, then work on all this relative stuff after.

Glad to hear :blush:

Should we error or deprecate on nested matches to reserve breaking change space in the future?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ryansobol picture ryansobol  ·  3Comments

ackvf picture ackvf  ·  3Comments

ArthurRougier picture ArthurRougier  ·  3Comments

tomatau picture tomatau  ·  3Comments

Waquo picture Waquo  ·  3Comments