简体   繁体   English

功能组件仍然使用 react.memo 重新渲染

[英]functional component still rerender with react.memo

I want to make a quiz app with a countdown timer.我想制作一个带有倒数计时器的测验应用程序。 The timer use setinterval and the quiz has a functional component for Question.计时器使用 setinterval 并且测验具有问题的功能组件。 I have already set react.memo for the question function component.我已经为问题 function 组件设置了 react.memo。 But it keeps rerender each second.但它每秒都会重新渲染。 It works fine on desktop.它在桌面上运行良好。 But it flickers on mobile since the input for answer keep refocus但它在移动设备上闪烁,因为答案的输入不断重新聚焦

import { useEffect, useState, memo } from 'react';

function Game() {
  let interval;
  
  const [timer, setTimer] = useState(180000);
  
  useEffect(() => {
    interval = setInterval(() => {
      setTimer(timer - 1000);
    }, 1000);
    return () => {
      if (interval) {
        clearInterval(interval)
      }
    }
  }, [timer]);
  
  const QuestionComponent = memo(props => {
    return(<div></div>);
  });

  return (
    <>
      <div>{timer}</div>
      <QuestionComponent/>
    </>
  );
}

The above code is the Game component, which will be called from App component The question component keeps rerendering even there is nothing in it.上面的代码是 Game 组件,它会从 App 组件调用 question 组件一直重新渲染,即使里面什么都没有。

May anyone please advise?有人可以建议吗? Thank you very much非常感谢你

Ideally you should define your components outside your other components.理想情况下,您应该在其他组件之外定义您的组件。 As mentioned in comment, this line of code will run on every render.如评论中所述,这行代码将在每次渲染时运行。 Even if you use React.memo() , this line itself will run on every render, in contrast to writing it outside where it will run normally.即使你使用React.memo() ,这条线本身也会在每次渲染时运行,这与将它写在正常运行的地方不同。

If you are writing it inside, you have to persist the value between renders.如果你在里面写它,你必须在渲染之间保留值。 It can be done using useCallback because a react component is technically a function:它可以使用useCallback来完成,因为 React 组件在技术上是一个 function:

 const Component = useCallback(
    memo(() => {
      console.log("rerender");
      return <div></div>;
    }),
    []
  );

Or another way is using a ref.或者另一种方法是使用 ref。

import { useEffect, useState, memo, useMemo, useCallback, useRef } from "react";

function App() {
  let interval;

  const [timer, setTimer] = useState(180000);
  const componentRef = useRef();
  useEffect(() => {
    interval = setInterval(() => {
      setTimer(timer - 1000);
    }, 1000);
    return () => {
      if (interval) {
        clearInterval(interval);
      }
    };
  }, [timer]);

  useEffect(() => {
    const Component = memo(() => {
      console.log("rerender");
      return <div></div>;
    });
    componentRef.current = Component;
  }, []);

  return (
    <>
      <div>{timer}</div>
      <>{componentRef.current && <componentRef.current />}</>
    </>
  );
}

export default App;

Link 关联

But both above are hacks.但以上都是黑客。 And you will definitely run into issues when you use hooks.当你使用钩子时,你肯定会遇到问题。 Much better to just write it outside.最好把它写在外面。

const QuestionComponent = memo(props => {
    return(<div></div>);
});

import { useEffect, useState, memo } from 'react';

function Game() {
  let interval;
  
  const [timer, setTimer] = useState(180000);
  
  useEffect(() => {
    interval = setInterval(() => {
      setTimer(timer - 1000);
    }, 1000);
    return () => {
      if (interval) {
        clearInterval(interval)
      }
    }
  }, [timer]);
  
  return (
    <>
      <div>{timer}</div>
      <QuestionComponent/>
    </>
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM