在带有数组的单个函数中多次调用 `useVal` - 意外行为 [英] Calling `useVal` several times in a single function with arrays - unexpected behavior

查看:35
本文介绍了在带有数组的单个函数中多次调用 `useVal` - 意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在单个函数调用中多次调用我的 useArr 函数.每次调用 useArr 时,我都会向现有的 arr 函数推送一个新值.我用 pause 函数错开了每次调用.

它不是以逐步的间隔方式呈现 abcde 的字符串,而是简单地覆盖前一个字母.我对引擎盖下的钩子的理解不是很好,所以如果有人能提供见解,我将不胜感激.

为了说明我为什么要编写这个非常规代码的背景,我试图模拟 websocket 如何与应用程序交互,如果有人想知道的话:)

const App = () =>{const [arr, useArr] = useState([])返回 (<div>{arr}<button onClick={increment}>点击meh</button>

)异步函数增量(){useArr([...arr, 'a'])等待暂停()useArr([...arr, 'b'])等待暂停()useArr([...arr, 'c'])等待暂停()useArr([...arr, 'd'])等待暂停()useArr([...arr, 'e'])等待暂停()}异步函数暂停(){return new Promise(_=>setTimeout(_, 500))}}导出{应用}

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

解决方案

tl;dr:您应该使用

I'm calling my useArr function several times within a single function call. With each call to useArr, I'm pushing a new value to the existing arr function. I'm staggering each call with a pause function.

Instead of rendering the string of abcde in a stepwise, interval fashion, it simply overrides the previous letter. My understanding of hooks under the hood isn't great, so I'd appreciate if anyone could offer insight.

To give some context as to why I'm writing this unconventional code, I'm trying to simulate how a websocket would interact with the app, if anyone was wondering :)

const App = () => {
  const [arr, useArr] = useState([])
  return (
    <div>
      {arr}
      <button onClick={increment}>Click meh</button>
    </div>
  )
  async function increment() {
    useArr([...arr, 'a'])
    await pause()
    useArr([...arr, 'b'])
    await pause()
    useArr([...arr, 'c'])
    await pause()
    useArr([...arr, 'd'])
    await pause()
    useArr([...arr, 'e'])
    await pause()
  }
  async function pause() {
    return new Promise(_=>setTimeout(_, 500))
  }
}

export { App }

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

解决方案

tl;dr: You should be using the functional update syntax.

This is really more about understanding JavaScript closures than it is about hooks. To demonstrate what is going on, here is some code based on your increment method, but without any hooks -- just plain JavaScript.

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...arr, 'b'];
    await pause()
    nextArr = [...arr, 'c'];
    await pause()
    nextArr = [...arr, 'd'];
    await pause()
    nextArr = [...arr, 'e'];
    await pause()
  }

At the end of this function, what do you expect the value of nextArr to be? ['a', 'b', 'c', 'd', 'e'] or ['e'] (hint: you've already seen the result in your app)

nextArr represents what you are passing in to your state setter.

As a side note, I recommend you use the naming convention of setArr rather than useArr for the setter variable name. useX should be reserved for custom hooks -- not used for state setters.

What you meant to be doing is something like the following:

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...nextArr, 'b'];
    await pause()
    nextArr = [...nextArr, 'c'];
    await pause()
    nextArr = [...nextArr, 'd'];
    await pause()
    nextArr = [...nextArr, 'e'];
    await pause()
  }

This code leverages the previous value to create the next value. The functional update syntax can be used to get this effect. With the functional update syntax and the naming change I suggested, your increment function would look like this:

  async function increment() {
    setArr(prevArr => [...prevArr, 'a'])
    await pause()
    setArr(prevArr => [...prevArr, 'b'])
    await pause()
    setArr(prevArr => [...prevArr, 'c'])
    await pause()
    setArr(prevArr => [...prevArr, 'd'])
    await pause()
    setArr(prevArr => [...prevArr, 'e'])
    await pause()
  }

这篇关于在带有数组的单个函数中多次调用 `useVal` - 意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆