react-runner icon indicating copy to clipboard operation
react-runner copied to clipboard

Use of import and importCode unclear + infinite render loop when adding scope

Open Tyrannogyna opened this issue 2 years ago • 2 comments

Hi!

I would like to add my own files to the Scope but the Readme is not clear enough on what localFileContent and baseScope means:

import { importCode } from 'react-runner'
import * as YourPkg from 'your-pkg'

const baseScope = {
  /* base globals */
}

const scope = {
  ...baseScope,
  // scope used by import statement
  import: {
    constants: { A: 'a' },
    'your-pkg': YourPkg,
    './local-file': importCode(localFileContent, baseScope),
  },
}

If I have import Button from "./button"; I would assume the following code is what's expected (taking into account that importCode's signature expects a string as the first param and Scope as the second. However I get the error 'Button is not defined'.

scope: {
            import: {
                "./button": importCode("Button", {})
            }
        }

On top of that, if I add scope to useRunner, my component enters into an infinite rerender loop, even if I just add scope:{}, which I don't know what causes it or how to stop it. Here is my current code, very minimalistic for now. Any help on how to solve any of the two issues would be greatly appreciated

import React, { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import { useRunner, Scope, importCode } from "react-runner";
import styled from "styled-components";
import { CodeEditor } from "react-live-runner";
import Button from "./button";

import "./index.css";

interface RunnerProps {
  code: string
  scope?: Scope
  transformCode?: (code: string) => string
  language?: string
}

const buttonCode = `
  import Button from "./Button";
  
  <Button
      id="potato"
      disabled="false"
      height="40"
      highlight="true"
      text="My button"
      type="button"
      width="200"/>
`;

export default function App() {
    createRoot(document.getElementById("root") as HTMLElement).render(
        <React.StrictMode>
            <UseRunner code={buttonCode} transformCode={undefined} />
        </React.StrictMode>
    );
}

function UseRunner({
    code: initialCode,
    transformCode
}: RunnerProps) {
    const [code, setCode] = useState<string>(initialCode ?? "<h3>Code is missing!</h3>");

    const { element, error } = useRunner({
        code: transformCode ? transformCode(code) : code,
        scope: {
            import: {
                "./button": importCode("<Button />", {})
            }
        }
    });

    useEffect(() => {
        setCode(initialCode);
    }, [initialCode]);

    return (
        <Container>
            <EditorContainer>
                <Editor value={code} />
            </EditorContainer>
            <PreviewContainer>
                <Preview>{element}</Preview>
                {error && <PreviewError>{error}</PreviewError>}
            </PreviewContainer>
        </Container>
    );
}

And this is the error on the browser' console when trying to look at the code any time I try to set scope. The issue is not with useEffect itself as I've done tests removing it completely.

684 react-dom.development.js:86 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
    at UseRunner (http://localhost:3000/main.8b244c7fd6a37a177bc4.hot-update.js:101:11)

Tyrannogyna avatar Sep 28 '23 16:09 Tyrannogyna

Hi @Tyrannogyna, Long time since you asked this. I am not one of the maintainers of the project but I have been able to import my own code. I am seeing some issues in your example. If you create a small repo with a minimum set up, I can try to fix it taking as a base what I already have. Regards

elchininet avatar Dec 04 '24 15:12 elchininet

Use useMemo to cache the scope will solve the issue.

lit26 avatar Jan 03 '25 05:01 lit26