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

[BUG] Out of the box, cannot access lexical declaration 'root' before initialization #10

Open
PauMAVA opened this issue Aug 24, 2024 · 6 comments

Comments

@PauMAVA
Copy link

PauMAVA commented Aug 24, 2024

Hello!

I was trying to use this library in my SolidJS library project and I have found a problem. I tried to create a <Motion.div> element like this:

const appliedAnimation = {
    unmount: {
      opacity: 0,
    },
    mount: {
      opacity: 1,
    },
}
let [open, setOpen] = createSignal(true);
...
return (
    <>
      {open() && (
        <Motion.div
          {...rest}
          class={classes}
          initial={appliedAnimation.unmount}
          exit={appliedAnimation.unmount}
          animate={open() ? appliedAnimation.mount : appliedAnimation.unmount}
          transition={{ duration: 0.5 }}
        >
          {icon && iconTemplate}
          <span class={contentClasses}>{value}</span>
          {onClose && !action && <span>TODO</span>}
          {action || null}
        </Motion.div>
      )}
    </>
)

When I try to visualize the component I get the following error:

Uncaught ReferenceError: can't access lexical declaration 'root' before initialization
<anonymous> index.js:5450
createAndBindMotionState index.js:5434
runComputation index.js:184
updateComputation index.js:174
createEffect index.js:64
createAndBindMotionState index.js:5432
MotionComponent index.js:5450

Digging a little bit into solid-motionone I found that the conflicting line is inside the MotionComponent:

const [state, style] = createAndBindMotionState(
() => root,
() => ({...options}),
useContext(PresenceContext),
useContext(ParentContext),
)
let root!: Element
return (
<ParentContext.Provider value={state}>

As it can be seen the root variable is declared after it's reference into the arrow function? For me the transpiled code appears as:

var MotionComponent = (props) => {
  const [options, , attrs] = splitProps(props, OPTION_KEYS, ATTR_KEYS);
  const [state, style2] = createAndBindMotionState(() => root, () => ({
    ...options
  }), useContext(PresenceContext), useContext(ParentContext));
  let root;
  return createComponent(ParentContext.Provider, {
  ...

I'm quite new to solid-js, sorry if I'm missing something obvious here. I also tried to but the let root before the createAndBindMotionState call, and then the error is Animation state must be mounted with valid Element.

Finally here's a little bit of info about versions:

  • solid-js: ^1.8
  • solid-motionone: ^1.0.0

Thanks in advance! 😁

@thetarnav
Copy link
Member

The code is correct
you can use variables in callbacks that are declared below
because it all depends on the order of execution
if the callback is ran after the variable has been declared, it's all good
Here, the ref needs to be assigned first before it can even be used so the placement of the variable in the component shouldn't matter
Changing the order won't fix the code, just change the error message
But what's weird is that the callback is being called immediately
As you can see the element callback is ran in an effect, which should happen after the elements have been created and ref declared and assigned with the html element.
Effects in solid are scheduled to run at the end of a internal queue, which is created by effects, roots, render calls, etc.
If the effect executes immediately, it means that there in no such queue that is can attach to, it has to run as soon as it's created.
If you don't have any other issues in you app, then my guess would be that your app and solid-motionone are using two different versions of solid at the same time, and the effects queue that solid in your app creates, is not the same that solid from solid-motion one expects. Thats just a quess but something like that is fairly common.
Can you make sure that is not the case or provide a minimal repro to try out?
You can confirm that this is an issue by doing something like this:

// somewhere in your app and in solid-motionone
import {createSignal} from "solid-js"
if (!window.createSignal) {
	window.createSignal = createSignal
} else {
	console.log(window.createSignal === createSignal ? "Good" : "Bad")
}

@greypants
Copy link

greypants commented Oct 14, 2024

I've got the same issue. I confirmed both solid-motionone and the app are using the same version of solid-js using the method above.

I'm working on a component library, and the code runs fine in my demo app, but fails in another app. I'll post if I figure something out.

    "solid-js": "1.9.1",
    "solid-motionone": "1.0.2",

@greypants
Copy link

greypants commented Oct 14, 2024

Figured out our root issue. The app with the failure had some weird setup logic around the initial render that was causing this Solid warning to log:

computations created outside a `createRoot` or `render` will never be disposed

This stack overflow post helped explain it.

Once I addressed the Solid warning, the above referenced issue went away.

@greypants
Copy link

It might be nice to add a check in the code for root to be defined, and to throw a more helpful error if it's missing.

@thetarnav
Copy link
Member

I wouldn't mind having some nice error message that links to this issue during development

@PauMAVA
Copy link
Author

PauMAVA commented Oct 20, 2024

If you don't have any other issues in you app, then my guess would be that your app and solid-motionone are using two different versions of solid at the same time, and the effects queue that solid in your app creates, is not the same that solid from solid-motion one expects. Thats just a quess but something like that is fairly common.

Indeed, this was the problem I was programming a component library and using solid-motionone on my playground project as well as in the component library project. This caused two different versions of solidjs to be running.

I wouldn't mind having some nice error message that links to this issue during development

This would be nice though, since I spent couple of hours trying to find the root cause of the problem. I totally understand this is not a solid-motionone issue but it would be a niceity plus. Maybe we could add the same check you advised me to use:

function checkDupedSolid() {
    if (!window._smoCheck ) {
	window._smoCheck = createSignal
    } else {
	if (window._smoCheck !== createSignal) {
            console.warn('There is more than one instance of solid running. This may cause errors in the use of this library.')
        }
        window._smoCheck = undefined;
    }
}

checkDupedSolid();

Thanks!

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

No branches or pull requests

3 participants