在 React 中一个字母一个字母地“打印”字符串

IT技术 javascript arrays reactjs string react-native
2021-05-07 19:52:52

我有一个 React Native 组件,它需要用一个字母一个字母一个字母地打印字符串的字母来显示一个动画。因此,从逻辑上讲,我需要在循环中更新 React 状态挂钩,以 1 秒的间隔将字符串的每个字符附加到它。到目前为止我所拥有的是:

let [placeholder, change_placeholder] = React.useState('');
const placeholder_print = () => {
    let temp = "Search for anything"
    console.log("Value of temp is now: " + temp)
    console.log("Length of string: " + temp.length)
    for (let i = 0; i < temp.length; i++) {
        console.log("Selected character is: " + temp.charAt(i))
        change_placeholder(placeholder.concat(temp.charAt(i)))
        console.log("Placeholder is now: " + placeholder)
    }
}

以及带有状态钩子的 React 组件:

<View>
    <Text>{placeholder}</Text>
</View>

是的,我知道这不会动画。但是最后for, 的值placeholder逻辑上应该是字符串本身,对吗?如果是这样,我可能能够setTimeout()在 for 循环内部绕过动画部分以每秒运行一次。但是,这placeholder_print()是运行时的输出

[Fri Jan 15 2021 16:29:30.166]  LOG      Value of temp is now: Search
[Fri Jan 15 2021 16:29:30.168]  LOG      Length of string: 6
[Fri Jan 15 2021 16:29:30.169]  LOG      Selected character is: S
[Fri Jan 15 2021 16:29:30.170]  LOG      Placeholder is now:
[Fri Jan 15 2021 16:29:30.170]  LOG      Selected character is: e
[Fri Jan 15 2021 16:29:30.170]  LOG      Placeholder is now:
[Fri Jan 15 2021 16:29:30.171]  LOG      Selected character is: a
[Fri Jan 15 2021 16:29:30.171]  LOG      Placeholder is now:
[Fri Jan 15 2021 16:29:30.171]  LOG      Selected character is: r
[Fri Jan 15 2021 16:29:30.172]  LOG      Placeholder is now:
[Fri Jan 15 2021 16:29:30.172]  LOG      Selected character is: c
[Fri Jan 15 2021 16:29:30.172]  LOG      Placeholder is now:
[Fri Jan 15 2021 16:29:30.173]  LOG      Selected character is: h
[Fri Jan 15 2021 16:29:30.173]  LOG      Placeholder is now:

当在 Python 或什至没有状态挂钩的 vanilla JavaScript 中运行类似的逻辑时,这很好用。我不知道这是否需要使用<Animated>React Native 中组件来实现,或者它是否是 React 状态挂钩工作方式的一些根本区别。我被困在这里,伸出援手将得到支持。

1个回答

您没有在 for 循环中看到更新的原因是它setState()是异步的,并且更新的状态值在下一次渲染之前不可用所以你只是循环你的字符串,记录当前状态值(这是一个空字符串),然后调用setState将在循环完成后调用请参阅:setState() 之后的 Console.log() 不返回更新的状态

在 React 的上下文中考虑这样的循环时,您需要考虑更大的状态/渲染周期。动画的“循环”实际上是由状态变化触发的连续渲染。

useEffect钩子为您提供了一种利用此循环的内置方法,这意味着您只需要跟踪index顺序渲染(该代码段用于useRef保留值)并使用它来更新状态,从而触发新的渲染等。

这是一个快速片段。

const App = () => {
  const [placeholder, setPlaceholder] = React.useState('');

  const
    string = 'This is the final string.',
    index = React.useRef(0);

  React.useEffect(() => {
    function tick() {
      setPlaceholder(prev => prev + string[index.current]);
      index.current++;
    }
    if (index.current < string.length) {
      let addChar = setInterval(tick, 500);
      return () => clearInterval(addChar);
    }
  }, [placeholder]);

  return (
    <div>
      {placeholder}
    </div>
  )
}


ReactDOM.render(
  <App />,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>