useState останавливает поток рендеринга в useFrame, используя реагирующее три волокна - PullRequest
0 голосов
/ 27 апреля 2020

Я перевожу проект, который у меня был в три js, чтобы отреагировать на три волокна, и у меня возникли некоторые проблемы с рендерингом l oop. Может быть, я не совсем понимаю, как работает useFrame.

Вот кодовый ящик:

https://codesandbox.io/s/react-three-test-y0zrx?file= / src / Three.jsx: 1824-1835

Так что в этом проекте я использую прокрутку для перемещения камеры по оси z и изменения года, отображаемого, когда мы достигаем различных точек в позиции z. Как вы можете видеть, когда мы достигаем этой точки, мы используем функцию set useState, которая изменяет состояние, но также создает задержку и на мгновение деактивирует эффекты рендеринга.

Это функция визуализации, которая изменяет отображаемую информацию (год от позиции):

ThreeComponent.jsx

const getYear = cameraZ => parseInt(cameraZ / -10 + START_YEAR, 10);
const getRoundedYear = year => Math.round(year / 10) * 10;

const shouldDisplayYear = roundedYear => {
    return (
      roundedYear % 100 === 0 || (roundedYear > 1890 && roundedYear % 10 === 0)
    );
  };

  function Renderer() {
    const composer = useRef();
    const { scene, gl, camera } = useThree();
    useFrame(() => {
      const roundedYear = getRoundedYear(getYear(camera.position.z));
      if (shouldDisplayYear(roundedYear)) {

        // The problem lies here
        setDisplayedYear(roundedYear);
      }
      return composer?.current?.render();
    }, 1);
    return (
      <effectComposer ref={composer} args={[gl]}>
        <renderPass attachArray="passes" scene={scene} camera={camera} />
        <bokehPass
          attachArray="passes"
          args={[
            scene,
            camera,
            {
              focus: 20.0,
              aperture: 1.1 * 0.00008,
              maxblur: 0.05,
              width: window.innerWidth,
              height: window.innerHeight
            }
          ]}
        />
      </effectComposer>
    );
  }
  ...
  return (
    <div className="three-component" ref={canvasRef}>
      <Canvas
       ...>
       ...
       <Renderer/>
      </Canvas>
     </div>
  );

Заданная функция передается из родительского компонента, но имеет ту же проблему, если он находится на том же компоненте:

ThreeComponent.jsx

const ThreeComponent = ({ setDisplayedYear, startYear }) => {

Приложение. js (Родитель)

  const [displayedYear, setDisplayedYear] = useState(START_YEAR);

Может ли кто-нибудь пролить свет на то, почему происходит это отставание? Или, может быть, есть лучший способ перемещать камеру только с помощью прокрутки и обновления номера.

Большое спасибо!

1 Ответ

0 голосов
/ 27 апреля 2020

useFrame - это рендер-l oop, он работает 60 раз в секунду, у вас не может быть побочных эффектов. setDisplayedYear попросит реагировать, чтобы сделать все его тяжелые подъемы, разбираться, проходя через vdoms и т. д. c. в лучшем случае это снизит производительность или просто убьет вкладку.

Есть много вещей, которые вы можете сделать здесь, лучше всего будет изменить камеру прямо сейчас и там. Вы получаете его из useState (state => state.camera. Я бы удалил все вещи setState.

edit:

Я думаю, что вы также без необходимости заново создаете много объектов там при каждом рендеринге. Например, функция Renderer () создается каждый раз, когда изменяется setState, она заново создает весь материал эффектов с нуля. Компоненты всегда должны быть фиксированными ссылками.

Вот пример, в котором камера работает в и вне: https://codesandbox.io/s/r3f-lod-rzuj1

вот еще один, который, вероятно, ближе к тому, что вам нужно (камера реагирует на смещение прокрутки): https://codesandbox.io/s/adoring-feather-nk16u

...