尝试通过 React useRef 钩子使用画布时,传递给 checkMaxIfStatementsInShader 的无效值 0

问题描述 投票:0回答:1

我创建了一个简单的 React 应用程序,它使用 PixiJS 并且运行良好。

无论浏览器窗口宽度如何,画布的 1:1 宽高比都是通过

ResizeObserver
保持的,如下所示:

animated screenshot

但是,我必须在那里使用解决方法:我让

PIXI.Application
动态创建一个画布元素,然后将其分配给React
childRef.current
,如下所示:

const PixiGame = () => {
  const parentRef = useRef(null);
  const childRef = useRef(null);  // as a workaround I have to assign the canvas element below, created by PIXI app

  useEffect(() => {

    const parentElement = parentRef.current;

    const app = new Application({
      backgroundColor: 0xccffcc,
      width: 800,
      height: 800,
    });

    // the PIXI app has created a canvas element - make it a child of the parent div
    const childElement = app.view;
    childElement.id = "child";
    childElement.classList.add("child");
    childRef.current = childElement;
    parentElement.appendChild(childElement);

当我尝试采用更自然的方式并在其他类似应用程序的JSX中声明canvas元素时,我收到错误消息:

Error: Invalid value of `0` passed to `checkMaxIfStatementsInShader`
    at checkMaxIfStatementsInShader (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5189:11)
    at _BatchRenderer2.contextChange (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8129:27)
    at Runner.emit (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5340:22)
    at ContextSystem.initFromContext (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8619:155)
    at ContextSystem.initFromOptions (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8631:10)
    at ContextSystem.init (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:8603:168)
    at Runner.emit (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:5340:22)
    at StartupSystem.run (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:11443:27)
    at new _Renderer2 (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:13203:478)
    at autoDetectRenderer (https://masterdetailpixidynamic-hn0o--5173--41fbae16.local-corp.webcontainer.io/node_modules/.vite/deps/pixi__js-legacy.js?v=b911e8ad:12931:14)

这是我尝试使用的代码,其中画布元素在 JSX 中定义:

const PixiGame = () => {
  const parentRef = useRef(null);
  const childRef = useRef(null);

  useEffect(() => {
    const parentElement = parentRef.current;
    const childElement = childRef.current;  // here I just use the existing canvas element, defined in JSX below

    const app = new Application({
      backgroundColor: 0xccffcc,
      width: 800,
      height: 800,
      view: childElement,
    });

    const resizeObserver = new ResizeObserver((entries) => {
      for (let entry of entries) {
        const { width, height } = entry.contentRect;
        const minDimension = Math.floor(Math.min(width, height));

        // maintain the 1:1 aspect ratio of the child element
        childElement.style.width = `${minDimension}px`;
        childElement.style.height = `${minDimension}px`;
      }
    });

    resizeObserver.observe(parentElement);

    const background = new Graphics();
    for (let i = 0; i < 8; i++) {
      for (let j = 0; j < 8; j++) {
        if ((i + j) % 2 == 0) {
          background.beginFill(0xccccff);
          background.drawRect(i * 100, j * 100, 100, 100);
          background.endFill();
        }
      }
    }
    app.stage.addChild(background);

    const texture = Texture.from("https://pixijs.com/assets/bunny.png");
    const bunny = new Sprite(texture);
    bunny.anchor.set(0.5);
    bunny.x = 50;
    bunny.y = 50;
    bunny.width = 100;
    bunny.height = 100;
    app.stage.addChild(bunny);

    return () => {
      resizeObserver.unobserve(parentElement);
      resizeObserver.disconnect();
      parentElement.removeChild(childElement);
      app.destroy(true, true);
    };
  }, []);

  return (
    <div className="verticalFlexContainer">
      <div className="hint">Game No. 1 Score1:Score2</div>
      <div className="parent" ref={parentRef}>
        <canvas className="child" id="child" ref={childRef}></canvas>
      </div>
      <div className="status">A game hint to do this and that...</div>
    </div>
  );
};

该错误似乎与 React 生命周期或其严格模式有关......

我尝试打印

childRef.current
parentRef.current
,但它们永远不会为空。

有人建议如何在我的应用程序的 JSX 部分中定义画布,并且仍然能够在 Pixi 代码中使用它吗?

PS:是的,我已经尝试过CSS

aspect-ratio: 1
,但它对我来说效果不佳,这就是我使用
ResizeObserver
的原因。

PPS:不,我不想使用“@pixi/react”包,因为我想以命令式(而不是声明式)风格使用 PixiJS,而且它似乎工作得足够好。

javascript reactjs pixi.js react-ref
1个回答
0
投票

没有太多时间玩它,但它可能会有所帮助。

App.destroy() 函数被描述为从 DOM 中删除 canvas 元素,因此当你的 useEffect 运行 cleanup 时,它会从 JSX 中销毁 canvas 元素。

在第一个示例中,您在每次 useEffect 运行时创建新的画布元素,但在第二个代码片段中,它在 JSX 中创建了一次 -> 在 unmound 时被删除 -> 并且没有重新创建,从而导致错误。

© www.soinside.com 2019 - 2024. All rights reserved.