Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: persist route (don't unmount when navigate out) #204

Open
illiaChaban opened this issue Nov 21, 2022 · 5 comments
Open
Labels
enhancement New feature or request

Comments

@illiaChaban
Copy link

Describe the bug

Not a bug, but no templates for feature requests.

I want to be able to avoid rerendering a previously visited route and the route should keep all the internal state.

"persist?: boolean" prop would be nice
Syntax proposal:

<Routes><Route path="/" persist element={...} /> </Routes>

The way I accomplish it right now:

        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/stack" />
          ...
        </Routes>
        <PersistRoute path="/stack" component={StackTest} />


export const PersistRoute = (p: { path: string; component: FC }) => {
  const match = useMatch(() => p.path)

  let dispose: () => void | undefined
  const render = once(() => {
    return createRoot(_dispose => {
      dispose = _dispose
      return <p.component />
    })
  })

  onCleanup(() => dispose?.())

  return <Show when={match()}>{render()}</Show>
}

Your Example Website or App

https://github.com/solidjs/solid-router

Steps to Reproduce the Bug or Issue

None

Expected behavior

When has "persist" prop it should mount the component on first visit and not cleanup on navigate out

Screenshots or Videos

No response

Platform

all

Additional context

No response

@ryansolid
Copy link
Member

This sort of approach works for now but it is less than ideal since offscreen stuff is "live". I don't think we could make that a general solution. But I have an idea of how to do an "Offscreen" mechanism for the future.

@ryansolid ryansolid added the enhancement New feature or request label Aug 8, 2023
@MrFoxPro
Copy link

MrFoxPro commented Sep 6, 2023

For now I ended up with this:

function once(fn: Function, onAccess?) {
   let acc = () => {
      const { toReturn, target } = fn!()
      onAccess?.(target)
      acc = () => {
         onAccess?.(target)
         return toReturn
      }
      return toReturn
   }
   return () => acc()
}

function persist(Comp: Component) {
   let routerRoot = document.body

   const [node, setNode] = createSignal<HTMLElement>(null)
   let rendered = false
   function onAccess(val) {
      // Init component
      // This is needed to trigger it hooks
      let output = val()

      let i = 0
      while (output?.constructor === Function) {
         if (i > 10) throw new Error("Something bad happened in routing!")
         output = output()
         i++
      }
      if (output) setNode(output)
   }
   createEffect(() => {
      const n = node()
      if (!n || !routerRoot) return

      if (!rendered) {
         console.log(n, routerRoot.firstChild)
         routerRoot.insertBefore(n, routerRoot.firstChild ?? null)
         rendered = true
      }
      n.style.visibility = "unset"
   })
   function onWrapperShouldUnmount() {
      const n = node()
      if (!n) return

      n.style.visibility = "hidden"
      setNode(null)
   }
   const FakeComponent = () => {
      const comp = <Comp ref={setNode} />
      const target = () => {
         onCleanup(onWrapperShouldUnmount)
         return comp
      }
      return { toReturn: null, target }
   }
   return once(FakeComponent, onAccess)
}

@erodriguezds
Copy link

Hi @ryansolid , is there any progress on this, or an alternative solution or pattern? I think this is a valuable feature. Vue has a built-in component for this: keep-alive.

The use-case I have is: we're building a dashboard SPA using Solidjs (btw: best decision we've ever made 😉 ... such a wonderful DX)... we have a page/route where the user can generate reports... they navigate to a different page/module, and when they go back to the report page, everything is cleared, so they have to setup all the filters again and rebuild the reports. This is obviously a bad UX, and the solution other libraries/frameworks offer is something like Vue's <keep-alive> component.

I'd be really nice if Solidjs (or Solid-router?) had a similar feature, or at least, a documented pattern to achieve the same.

Keep on the good work Ryan. Solidjs is the best fvck$ng thing ever happened to the frontend universe, and I tell you so being myself an experienced Vue (2&3) and React developer.

@Brendan-csel
Copy link
Contributor

Brendan-csel commented Jan 11, 2024

Could you possibly store the data for the filter/report page globally so it persists independent of the router? Perhaps even in local storage if you want it to persist across page refreshes.

Or if that is not appropriate then use a nested(parent) route to store the data (and provide via context) so it persists for as long as the user is within a subsection of the router tree. We use this approach when we have a pair of list and detail pages and we want to keep the list data around while the user is in the detail page.

@ryansolid
Copy link
Member

@erodriguezds keep-alive is a pretty difficult to make the way Solid works today as I was mentioning above. Vue's keep-alive does disconnect side effects and we don't have the means to do this before Solid 2.0. I didn't go out and say it in my response but that was where my idea for "Offscreen" for the future lies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants