1

Remix is prone to the following error when using import on top-level components TypeError: Cannot read properties of undefined (reading 'root').

So I've done as they recommend and have the following imports.server.tsx file.

export * from "lottie-react";

Then my component app.tsx looks exactly like this lottie example.

import React from "react";
import * as Lottie from "../imports.server";
import groovyWalkAnimation from "../../public/assets/102875-cinema-clap.json";

export default function App() {
  return (
    <>
      <h1>lottie-react - Component</h1>
      <Lottie animationData={groovyWalkAnimation} />;
    </>
  );
}

but I get the following error

JSX element type 'Lottie' does not have any construct or call signatures.ts(2604)

Edit 1:

The following seems to have worked for imports:

imports.server.tsx



import Lottie from "lottie-react";
export default Lottie;



AppTry.tsx



import React from "react";
import Lottie from "../imports.server";

import groovyWalkAnimation from "../../public/assets/102875-cinema-clap.json";

export default function AppTry() {
  // console.log(LottieModule);
  return (
    <>
      <h1>lottie-react - Component</h1>
      <Lottie animationData={groovyWalkAnimation}></Lottie>
    </>
  );
}

Now the various paramaters like "animationData" and "autoPlay" pop up on the Lottie component which I assume means the import is working? However I am now getting this error when rendering AppTry.tsx?

react.development.js:220 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of AppTry.

Edit 2:

import { useLottie } from "lottie-react";
import Lottie from "lottie-react";
import groovyWalkAnimation from "../../public/assets/102875-cinema-clap.json";

const Example = () => {
  const options = {
    animationData: groovyWalkAnimation,
    loop: true,
    autoplay: true,
  };

  const { View } = useLottie(options);

  return View;
};

const Example1 = () => {
  return <Lottie animationData={groovyWalkAnimation} />;
};

export const TopicOverview = () => {

  return (
    <div className="space-y-20">
      <Example1></Example1>
      <Example></Example>
    </div>
  );
};
rowen
  • 49
  • 6

3 Answers3

0

Looks like it has to do with your way of importing Lottie.

Shouldn't you import Lottie like this?:

import Lottie from "lottie-react";
Gobli
  • 327
  • 2
  • 12
  • As I said above, remix has this issue. See here https://remix.run/docs/en/v1/pages/gotchas hence the import statement. If I try `import Lottie from "../imports.server";` I get the following error "Module imports.server has no default export" – rowen Apr 26 '22 at 14:55
  • I'm pretty sure Gobli is on the right track. You may need to play around with your imports.server.tsx a bit more (eg based on the error message you posted maybe define Lottie as the default export?). I don't know how `export * from...` handles defaults, but that's worth looking into. `import * as Lottie` is always going to fail due to the fact that you're importing the entire module as Lottie, whereas `import Lottie from "lottie-react";` is importing a specific item from the module. – Stephen Sisk Apr 27 '22 at 17:35
  • I've edited my post, made at-least some progress. Any ideas? Does that seem right? – rowen Apr 28 '22 at 08:26
  • I'm quite sure you don't need the imports.server for Lottie, as it's a Client side library and the Remix Gotcha that you point out refers to server side code. Maybe the ```TypeError: Cannot read properties of undefined (reading 'root')``` comes from another place? – Gobli Apr 28 '22 at 08:47
  • Hmm but where from, I've implemented the components exactly as [they](https://github.com/Gamote/lottie-react) do in their example. I'll edit now and show you what it looks like. – rowen Apr 28 '22 at 11:25
0

I also struggled to get this working in Remix. You can do the lazy load import somewhere higher up in the tree too.

import type { LottiePlayer } from "@lottiefiles/lottie-player";
import { useEffect } from "react";

interface LottieCompProps {
  src: LottiePlayer["src"];
  style?: Partial<LottiePlayer["style"]>;
}

function LottieComp({ src, style = {} }: LottieCompProps): JSX.Element | null {
  // NB: otherwise, will cause app to crash. see https://remix.run/docs/en/v1/guides/constraints#third-party-module-side-effects
    useEffect(() => {
      import("@lottiefiles/lottie-player");
    },[]);

  if (typeof document === "undefined") return null;
  return (
    //@ts-expect-error dynamic import
    <lottie-player
      autoplay
      loop
      mode="normal"
      src={typeof src === "string" ? src : JSON.stringify(src)}
      style={{
        ...{
          width: "100%",
          backgroundColor: "transparent",
        },
        ...style,
      }}
    />
  );
}

export default LottieComp;
mattf96
  • 1
  • 1
0

The issue was in my root.tsx, an ErrorBoundary() function that called an <UnexpectedErrors/> component. This same component was being called in various slug.tsx files. For some reason remix did not like this.

Having two different <UnexpectedErrors/> and <UnexpectedErrors2/> components - one for the slug.tsx files and one for the index.tsx files fixed this.

rowen
  • 49
  • 6