首页 > 解决方案 > React 中的打字机效果

问题描述

我正在尝试在 React 组件中制作打字效果。我传入一个字符串数组,并尝试在一段时间后逐个字符地渲染它们(使用 setTimeout)。这是我的代码

  state = {
    typeColor: {
      color: "blue"
    },
    typed: ""
  };

  componentDidMount() {
    this.props.typewriter.map(string => {
      console.log("1", string);
      return this.stringChecker(string);
    });
  }

  typeWriter(string) {
    if (string.length === 0) {
      return;
    }
    console.log("3", string);
    this.setState((state, props) => ({ typed: state.typed.concat(string[0]) }));
    console.log(this.state.typed);

    setTimeout(() => this.typeWriter(string.slice(1)), 120);
  }
  stringChecker(string) {
    console.log("2", string);
    if (string === "Qurram") {
      this.setState({ typeColor: { color: "blue" } });
    } else {
      this.setState({ typeColor: { color: "pink" } });
    }
    this.typeWriter(string);
  }

  render() {
    return <div style={this.state.typeColor}>{this.state.typed}</div>;
  }
}

现在我期待这个的执行流程是这样的:字符串数组的第一个元素在映射函数中被“选中”->我为第一个元素调用 stringchecker ->我为第一个元素调用打字机,并迭代人物。然后我回到地图功能并为下一个做同样的事情。似乎流程根本不是这样,而是在每个字符切片的两个字符串之间交替。如果有人可以向我解释这一点,我将不胜感激。非常感谢你

沙盒链接:https ://codesandbox.io/s/morning-dust-18nq5

标签: javascriptreactjs

解决方案


您可以简单地使用useEffect()钩子,在每次重新渲染(随机延迟)之后增加文本的可见部分(存储在组件的状态中),直到整个文本输出。

您可以在下面找到这个概念的现场演示:

const { useState, useEffect } = React,
      { render } = ReactDOM
      

const srcString = `That's the text I'm going to print out`

const Typewriter = ({srcString}) => {

  const [{content,carriage}, setContent] = useState({content:'',carriage:0})
       
  useEffect(() => {
    if(carriage == srcString.length) return
    const delay = setTimeout(() => {
      setContent({content:content+srcString[carriage], carriage: carriage+1})
      clearTimeout(delay)
    }, 0|(Math.random()*200+50))
  }, [content])
  
  return <span>{content}<span className="cursor">|</span></span>
  
}

render (
  <Typewriter {...{srcString}} />,
  document.getElementById('root')
)
.cursor{animation:1s blink step-end infinite}@keyframes blink{from,to{color:transparent}50%{color:#000}}@-moz-keyframes blink{from,to{color:transparent}50%{color:#000}}@-webkit-keyframes blink{from,to{color:transparent}50%{color:#000}}@-ms-keyframes blink{from,to{color:transparent}50%{color:#000}}@-o-keyframes blink{from,to{color:transparent}50%{color:#000}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>


推荐阅读