每次调用 setState 时 React 打字动画都会重新启动

React typing animation restarts every time setState is called

我为每个页面的 headers/titles 设置了 react-typing-animation 的投资组合。在state用于某事的页面,打字动画还没有打完title调用setState,打字动画重新开始。

例如,在我的主页上我要添加一个漂亮的背景滚动效果,我有状态设置来跟踪 Y 轴上的滚动,所以如果主页加载并且您向下滚动,标题会不断重置并在滚动时开始打字。它也在我的井字游戏页面上执行此操作,如果您在动画完成之前开始玩游戏,它会重新启动,因为您在井字棋板上的位置已存储在状态中。

example image

我假设我可能需要对状态和打字动画做一些处理。也许以某种方式将动画存储在状态中并将其传递给您访问的每个页面?我不确定。

这是主页的一个片段:

import React, { useState, useEffect } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Box from "@material-ui/core/Box";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";

import GitHubCard from "../apps/githubCard/index";
import Bio from "../apps/bio/bio";
import AnimatedTypingComponent from "../anim/headerType";

import styles from "./homepage.module.scss";

const useStyles = makeStyles((theme) => ({
    root: {
        flexGrow: 1,
    },
    columns: {
        padding: theme.spacing(2),
        textAlign: "center",
        width: "100%",
    },
}));

// This will be the landing page for our application.
export default function HomePage() {
    const classes = useStyles();
    const [offsetY, setOffsetY] = useState(0);
    const handleScroll = () => {
        setOffsetY(window.pageYOffset);
    };

    useEffect(() => {
        window.addEventListener("scroll", handleScroll);
        return () => {
        window.removeEventListener("scroll", handleScroll);
        };
    }, []);

return (
    <div className={styles.homepage}>
        <div>
            <AnimatedTypingComponent title={"Hello I'm Russell Livermore"} title2={"Welcome to my portfolio"} />
        </div>
        

这是打字动画的代码

 import React from "react";
 import Typing from "react-typing-animation";

 import styles from "./header.module.scss";

export default function AnimatedTypingComponent(props) {
    const { title, title2 } = props;

    return (
        <div className={styles.header}>
            <Typing className={styles.typing}>
                <div id={styles.header}>{title}</div>

                <Typing.Delay ms={1000} />
                <div id={styles.wel}>{title2}</div>
            </Typing>
        </div>
    );
}

您可以使用React.memo来记忆您的组件以防止re-render

const MemoAnimatedTypingComponent  = React.memo(({...props}) => <AnimatedTypingComponent  {...props}/>);

在你的代码中

import React, { useState, useEffect } from "react";
import { makeStyles } from "@material-ui/core/styles";
import Box from "@material-ui/core/Box";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";

import GitHubCard from "../apps/githubCard/index";
import Bio from "../apps/bio/bio";
import AnimatedTypingComponent from "../anim/headerType";

import styles from "./homepage.module.scss";

const MemoAnimatedTypingComponent = React.memo(({...props}) => (
  <AnimatedTypingComponent {...props}/>
));

const useStyles = makeStyles((theme) => ({
  root: {
    flexGrow: 1,
  },
  columns: {
    padding: theme.spacing(2),
    textAlign: "center",
    width: "100%",
  },
}));

// This will be the landing page for our application.
export default function HomePage() {
  const classes = useStyles();
  const [offsetY, setOffsetY] = useState(0);
  const handleScroll = () => {
    setOffsetY(window.pageYOffset);
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

  return (
    <div className={styles.homepage}>
      <div>
        <MemoAnimatedTypingComponent
          title={"Hello I'm Russell Livermore"}
          title2={"Welcome to my portfolio"}
        />
      </div>
    </div>
  );
}

一个简单的例子

import React, { useEffect, useState } from "react";

const MemoComp = React.memo(({ ...props }) => <Test {...props} />);
function ClassSearch() {
  const [state, setState] = useState(1);
  return (
    <div>
      <button onClick={() => setState(state + 1)}>Increase</button> <br />
      <MemoComp data="memorized" /> <br />
      <Test data="original" /> <br />
    </div>
  );
}

export default ClassSearch;

const Test = ({ data }) => {
  const date = new Date().getTime();
  return (
    <>
      Test {date} {data}
    </>
  );
};