TanStack / router

🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering.
https://tanstack.com/router
MIT License
7.27k stars 495 forks source link

Issue on "/" paths #1

Closed diegodebonis closed 2 years ago

diegodebonis commented 5 years ago

Hi Tanner i figured it out that when we have the component like this

<LocationProvider>
    <nav>
      <Link to="/">Home</Link>
      <Link to="dashboard">Dashboard</Link>
      <Link to="invoices">Invoices</Link>
    </nav>
    <div>
      <MatchFirst>
      <Match path="/">
        {console.log('AAA')}
        <div>This is Home</div>
      </Match>
      <Match path="dashboard">
        <div>This is the Dashboard</div>
      </Match>
      <Match path="invoices">
        <MatchFirst>
          <Match path="/">
            {console.log('BBB')}
            <div>Invoices</div>
            <ul>
              <li>
                <Link to="new">New Invoice</Link>
              </li>
              <li>
                <Link to="1">Invoice 1</Link>
              </li>
              <li>
                <Link to="2">Invoice 2</Link>
              </li>
              <li>
                <Link to="3">Invoice 3</Link>
              </li>
            </ul>
          </Match>
          <Match path="new">
            <Link to="..">Back</Link>
            <div>This is a new invoice!</div>
          </Match>
          <Match path=":invoiceID">
            {({ params }) => (
              <div>
                <Link to="..">Back</Link>
                This is invoice #{params.invoiceID}
              </div>
            )}
          </Match>
        </MatchFirst>
      </Match>
      </MatchFirst>
    </div>
  </LocationProvider>

Both console.log execute is like we're missing some exact param or something else.

tannerlinsley commented 5 years ago

That's strange. / paths are forced to be exact all the time, and each Match should carry down its base via context.

tannerlinsley commented 5 years ago
diegodebonis commented 5 years ago

The thing is that it's kinda solved when you render the component like this

<LocationProvider>
    <nav>
      <Link to="/">Home</Link>
      <Link to="dashboard">Dashboard</Link>
      <Link to="invoices">Invoices</Link>
    </nav>
    <div>
      <MatchFirst>
      <Match path="/">
        {console.log('AAA')}
        <div>This is Home</div>
      </Match>
      <Match path="dashboard">
        <div>This is the Dashboard</div>
      </Match>
      <Match path="invoices">
        <MatchFirst>
          <Match path="new">
            <Link to="..">Back</Link>
            <div>This is a new invoice!</div>
          </Match>
          <Match path=":invoiceID">
            {({ params }) => (
              <div>
                <Link to="..">Back</Link>
                This is invoice #{params.invoiceID}
              </div>
            )}
          </Match>
          <Match path="/">
            {({ params }) => {
              console.log('BBB')
              return(<div>
                This is invoice /
              </div>)
            }}
          </Match>
        </MatchFirst>
      </Match>
      </MatchFirst>
    </div>
  </LocationProvider>

That way it only console.log 'BBB' or 'AAA' accodingly the route.

tannerlinsley commented 5 years ago

Can you make a codesandbox that replicates this behavior for me? I'm having a hard time replicating it on my end.

diegodebonis commented 5 years ago

Hi Tanner, here the example https://codesandbox.io/s/53jjln4654

You see that both console log executes, even when i enter to inovice. Only 1 console should execute.

Regards!

tannerlinsley commented 5 years ago

Nice. This is more clear. Thanks for the info. I'm still trying to figure out how or why this happens. Would be up to helping me investigate?

tannerlinsley commented 5 years ago

I feel like its some of this logic here: https://github.com/tannerlinsley/react-location/blob/master/src/index.js#L213-L220

niboc commented 5 years ago

Tanner, first of all I want to tell you that Diego and I are friends and we are talking about this topic since he discovered it.

My theory is that the child is rendered first, therefore the javascript code is executed, and then when rendering the parent, that child is hidden because it does not match the path, but the javascript has already been executed. On the other hand, when the child is a callback, this does not happen because the render trigger of the child occurs by the parent itself.

In conclusion, the routing works well, but the javascript of each Match child is executed regardless of whether match or no match

tannerlinsley commented 5 years ago

That shouldn't be the case, since we are inspecting the match child props before it is rendered.

On Thu, Jan 31, 2019 at 10:22 AM Nicolas Bocassi notifications@github.com wrote:

Tanner, first of all I want to tell you that Diego and I are friends and we are talking about this topic since he discovered it.

My theory is that the child is rendered first, therefore the javascript code is executed, and then when rendering the parent, that child is hidden because it does not match the path, but the javascript has already been executed. On the other hand, when the child is a callback, this does not happen because the render trigger of the child occurs by the parent itself.

In conclusion, the routing works well, but the javascript of each Match child is executed regardless of whether match or no match

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/tannerlinsley/react-location/issues/1#issuecomment-459430168, or mute the thread https://github.com/notifications/unsubscribe-auth/AFUmCRbsKlO1ofW6fEiiR5VWAB2sgDsUks5vIyZdgaJpZM4aLMpu .

niboc commented 5 years ago

So, you're trying to say that the console.log should not be executed unless it meets the condition of match? I'm not sure how the interpreter works, but I get the feeling that it's running before the rendering.

  <Match path="/">
    {console.log("AAA")}
    <div>This is Home</div>
  </Match>
  <Match path="invoices">
    <MatchFirst>
      <Match path="/">
        {console.log("BBB")}
        <div>Invoices</div>
      </Match>
    </MatchFirst>
  </Match>
</MatchFirst>

When replacing the child by callback the problem disappears, which makes me think that it is not a match problem.

  <Match path="/">
    {() => {
      console.log("AAA")
      return <div>This is Home</div>
    }}   
  </Match>
  <Match path="invoices">
    <MatchFirst>
      <Match path="/">
        {()=>{
          console.log("BBB")
          return <div>Invoices</div>
        }}
      </Match>
    </MatchFirst>
  </Match>
</MatchFirst>
tannerlinsley commented 5 years ago

I think you're right as well. I was merely pointing out that it's not designed to render the content unless it matches. That definitely narrows the bug type we're looking for.

niboc commented 5 years ago

Yes, I did not mean to render, that word came out but I wanted to refer to the assembly of the component regardless of whether it is rendered or not. What I'm not 100% sure, is that the execution of those console.log is correct, it would be ideal not.

I hope you can find the explanation of what happens :)

niboc commented 5 years ago

Great Job Tanner, this version seems to work perfect! Also the basepath works well.

Thanks!

tannerlinsley commented 5 years ago

Thanks!