solidjs-community/solid-transition-group

onMount called before elements are connected in outin mode

timothyallan opened this issue · 3 comments

I have a 3rd party component that relies on a document.getElementById call to find a DOM node in my components onMount function.

Works great with the normal transition, until I switch to an outIn transition, then my components onMount fires, but the DOM node doesn't exist yet, so the 3rd party component blows up.

I don't know exactly how it would look, but it would be great if there was a way to detect if the onMount was actually mounted and the DOM was ready, or if the component is floating around outside of the DOM in the transitions pretend onMount.

Just to add another use case: any forms using Felte, and its <ValidationMessage/> component will die when used inside a transition using outIn, as it looks for the the closest form element on mount... which doesn't exist.

Screen Shot 2023-03-22 at 4 45 58 PM

I still have to find a good solution to implement in the library, but this might be a good temporary workaround: https://stackblitz.com/edit/transition-group-out-in-onmount?file=src%2FApp.tsx

let onBeforeEnter: VoidFunction | undefined;
<Transition mode="outin" onBeforeEnter={() => onBeforeEnter!()}>
  <Show>
   {untrack(() => {
     const [added, setAdded] = createSignal(!onBeforeEnter);
     onBeforeEnter = () => setAdded(true);
     // only render the actual content if added to the DOM
     // unfortunatelly this needs <div> wrapper
     return <div>{added() && <MyComponent />}</div>;
   })}
  </Show>
</Transition>

It may not be the nicest thing to wire up, but if done correctly, could work better then trying to patch every onMount.

My other idea is to experiment with Suspense to defer the execution of effects... But maybe there is something simpler.


Here is the first solution abstracted to a component:

const TransitionChild: ParentComponent = props => {
  const [added, setAdded] = createSignal(false);
  useContext(TransitionCtx)(() => setAdded(true));
  return <div>{added() && props.children}</div>;
};

// then in the App (or where you add your Transition)

const TransitionCtx = createContext<(cb: VoidFunction) => void>();

function App() {
  let onBeforeEnter!: VoidFunction;
  return (
    <TransitionCtx.Provider value={cb => (onBeforeEnter = cb)}>
      <Transition mode="outin" onBeforeEnter={() => onBeforeEnter()}>
        {/* Any control-flow like Router, Outlet, Show, Switch, etc. */}
        <Show>
          {/* Needs to wrap every child */}
          <TransitionChild>
            {/* The actual element that will be transitioned */}
            <div>Hello</div>
          </TransitionChild>
        </Show>
      </Transition>
    </TransitionCtx.Provider>
  );
}
Huodoo commented

Transition with appear won't work if it has a outin mode parent Transition,