React – 循环内部的函数只被调用一次

huangapple go评论71阅读模式
英文:

React - function inside of a loop just gets called once

问题

以下是您要翻译的代码部分:

我在我的书籍组件中有一个点击处理程序用于翻转页面更准确地说它附加所需的类名到页面以便我可以设置页面翻转动画的CSS

// ---------- 处理书页上的点击事件 ---------- //

const handleClick = async (page) => {
  // 左页
  if (page === currentPage - 1 && page >= 2) {
    setFlippedPages((prevState) => ({
      ...prevState,
      [page]: "forward",
      [page - 1]: "forward",
    }));

    // 等待页面翻转过渡完成一半
    await new Promise((resolve) => setTimeout(resolve, 450));
    setCurrentPage(page - 1);
  }
  // 右页
  else if (page === currentPage) {
    setFlippedPages((prevState) => ({
      ...prevState,
      [page]: "backward",
      [page + 1]: "backward",
    }));

    // 等待页面翻转过渡完成一半
    await new Promise((resolve) => setTimeout(resolve, 450));
    setCurrentPage(page + 2);
  }
};
当用户想要跳转到第45页时我使用turnPages函数

// ---------- 翻页 ---------- //

const turnPages = async (page) => {
  for (let i = 2; i < page; i += 2) {
    await new Promise((resolve) => setTimeout(resolve, 900)); // 等待900毫秒
    console.log(i);
    handleClick(i);
  }
};
该函数以步长为2的方式迭代45页延迟为900毫秒但不幸的是handleClick只在第一次迭代中调用一次

我尝试了多种其他方法例如

const turnPages = (page) => {
  for (let i = 2; i < page; i += 2) {
    setTimeout(
      (i) => {
        handleClick(i);
        console.log(i);
      },
      900 * (i / 2),
      i
    );
  }
};


const turnPages = (page) => {
  const delayedClick = (i) => {
    setTimeout(() => {
      handleClick(i);
      console.log(i);
      if (i + 2 < page) {
        delayedClick(i + 2);
      }
    }, 900);
  };

  delayedClick(2);
};
我还在handleClick函数中返回了一个Promise以确保在进行下一次迭代之前函数已经完成这没有产生任何差异

// ---------- 处理书页上的点击事件 ---------- //

const handleClick = async (page) => {

...

// 解析Promise以指示页面翻转已完成
return Promise.resolve();
};
在turnPages函数中

const turnPages = async (page) => {
  for (let i = 2; i < page; i += 2) {
    await new Promise((resolve) => setTimeout(resolve, 900)); // 等待900毫秒
    await handleClick(i); // 等待handleClick完成
    console.log(i);
  }
};

为什么handleClick函数在第一次迭代中只调用一次?

编辑:

如@Stitt建议,我现在使用一个新的函数,以防用户点击目录中的条目。只执行一页翻转动画。

// --------------------- 处理目录点击 -------------------- //

const handleTocClick = async (page) => {
// 设置要翻转的页面
setFlippedPages((prevState) => ({
...prevState,
["2"]: "backward",
["3"]: "backward",
}));
// 等待页面翻转过渡完成一半
await new Promise((resolve) => setTimeout(resolve, 450));
setCurrentPage(page);
};

然后我完全删除了Turn Pages函数。

谢谢! React – 循环内部的函数只被调用一次


<details>
<summary>英文:</summary>

I have a click handler in my book component that flips pages or more accurately it appends the required classnames to the pages, so i can set the css for the page flip animation.

      // ---------- Handle the click event on the book pages ---------- //
    
      const handleClick = async (page) =&gt; {
        // left page
        if (page === currentPage - 1 &amp;&amp; page &gt;= 2) {
          setFlippedPages((prevState) =&gt; ({
            ...prevState,
            [page]: &quot;forward&quot;,
            [page - 1]: &quot;forward&quot;,
          }));
    
          // Wait for the page flip transition to be half complete
          await new Promise((resolve) =&gt; setTimeout(resolve, 450));
          setCurrentPage(page - 1);
        }
        // right page
        else if (page === currentPage) {
          setFlippedPages((prevState) =&gt; ({
            ...prevState,
            [page]: &quot;backward&quot;,
            [page + 1]: &quot;backward&quot;,
          }));
    
          // Wait for the page flip transition to be half complete
          await new Promise((resolve) =&gt; setTimeout(resolve, 450));
          setCurrentPage(page + 2);
        }
      };


when a user want to, for example go to page 45 I use the turnPages function


  

    // ---------- Turn Pages ---------- //
    
      const turnPages = async (page) =&gt; {
        for (let i = 2; i &lt; page; i += 2) {
          await new Promise((resolve) =&gt; setTimeout(resolve, 900)); // Wait for 900ms
          console.log(i);
          handleClick(i);
        }
      };

the function does the iteration of 45 page in steps of 2 at the right delay of 900ms, but unfortunately the handleClick just get called once in the first iteration.

I tried multiple other approaches like :

      const turnPages = (page) =&gt; {
        for (let i = 2; i &lt; page; i += 2) {
          setTimeout(
            (i) =&gt; {
              handleClick(i);
              console.log(i);
            },
            900 * (i / 2),
            i
          );
        }
      };

or 

      const turnPages = (page) =&gt; {
        const delayedClick = (i) =&gt; {
          setTimeout(() =&gt; {
            handleClick(i);
            console.log(i);
            if (i + 2 &lt; page) {
              delayedClick(i + 2);
            }
          }, 900);
        };
    
        delayedClick(2);
      };



I also returned a Promise inside the handleClick function to make sure the function has completed before moving to the next iteration. Which didn&#39;t do any difference.

      // ---------- Handle the click event on the book pages ---------- //
    
      const handleClick = async (page) =&gt; {
    
        ...
    
        // Resolve the promise to indicate completion of the page flip
        return Promise.resolve();
      }; 

and in the turnPages function:

      const turnPages = async (page) =&gt; {
        for (let i = 2; i &lt; page; i += 2) {
          await new Promise((resolve) =&gt; setTimeout(resolve, 900)); // Wait for 900ms
          await handleClick(i); // Wait for handleClick to complete
          console.log(i);
        }
      };


Why is the handleClick function only called once in the first iteration?



EDIT:

As suggested by @Stitt I am now using a new function in case the user clicks an entry in the table of contents. And only doing one page flip animation.


    // --------------------- Handle Table Of Contents Click -------------------- //
    
      const handleTocClick = async (page) =&gt; {
        // set the pages to be flipped
        setFlippedPages((prevState) =&gt; ({
          ...prevState,
          [&quot;2&quot;]: &quot;backward&quot;,
          [&quot;3&quot;]: &quot;backward&quot;,
        }));
        // Wait for the page flip transition to be half complete
        await new Promise((resolve) =&gt; setTimeout(resolve, 450));
        setCurrentPage(page);
      };


And I removed the Turn Pages function completely.
Thank! :)

</details>


# 答案1
**得分**: 1

我认为这个问题是因为您尝试在单个渲染中对状态进行多次更改所致(请参阅[useState][1]的文档)。第一次调用`handleClick`时,它将执行您的代码以处理右页块,最后一行是`setCurrentPage(page + 2);`。然而,这个更改直到您的`turnPages`函数完成后才会生效,这意味着您仍然是基于旧值`currentPage`进行计算。

为了解决这个问题,我建议为用户输入他们希望查看的页码编写一个新函数,该函数将**不**依赖于`handleClick`。请注意,这些与`useState`相关的问题也会适用于您的`setFlippedPages`函数,因此为了使其适用于多页,您可能需要进行较大程度的重写。也许不同的动画效果会更好,或者只是一个单页翻转动画,可以直接跳转到输入的页码。

  [1]: https://react.dev/learn/state-a-components-memory

<details>
<summary>英文:</summary>

I believe this issue is due to you attempting to make multiple changes to the state in a single render (see the documentation for [useState][1]). The first time you call `handleClick`, it will execute your code for the right-page block, concluding with the `setCurrentPage(page + 2);` line. This change will not be affected, however, until your `turnPages` function has completed, meaning that you are still computing based on the old value of `currentPage`.

In order to fix this issue, I&#39;d suggest writing a new function for when the user enters the page number they wish to view, which will **not** rely on `handleClick`. Note that these issues with `useState` will also apply to your `setFlippedPages` function, so you might be in for a semi-significant re-write in order for this to work for multiple pages. Perhaps a different animation will work better, or simply a single page flip animation which jumps directly to the page entered.


  [1]: https://react.dev/learn/state-a-components-memory

</details>



huangapple
  • 本文由 发表于 2023年5月28日 16:49:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76350675.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定