React Hooks:useState with onClick 仅更新第二次单击按钮?

Posted

技术标签:

【中文标题】React Hooks:useState with onClick 仅更新第二次单击按钮?【英文标题】:React Hooks: useState with onClick only updating the SECOND time button is clicked? 【发布时间】:2019-10-12 15:43:00 【问题描述】:

编辑:忘记了一个重要部分 - 如果您单击 Jeff A. Menges 旁边的按钮并检查控制台日志,就会发现这一点。

代码的重要部分是按钮代码的onClick中的“setFullResults(cardResults.data.concat(cardResultsPageTwo.data))”行。我认为它应该将 fullResults 设置为我告诉它的任何内容......除非它在您第一次单击它时不起作用。每次之后,它都会起作用,但不是第一次。这对下一组来说会很麻烦,因为我无法映射到未定义的数组,而且我不想告诉用户只需单击两次按钮即可获得实际的搜索结果。

我猜 useEffect 会起作用,但我不知道如何编写它或将它放在哪里。它显然不能在 App 功能组件的顶部工作,但我尝试将它放在其他任何地方都会给我一个错误。

我尝试了“this.forceUpdate()”,很多地方都推荐它作为快速修复(但建议不要使用 - 但我已经尝试了好几个小时),但是“this.forceUpdate( )" 无论我把它放在哪里都不是一个函数。

请帮助我在第一次单击此按钮时使其正常工作。


import React,  useState, useEffect  from "react";

const App = () => 

  let artistData = require("./mass-artists.json");

  const [showTheCards, setShowTheCards] = useState();
  const [fullResults, setFullResults] = useState([]);

  useEffect(() => 
    setFullResults();
  , []);

  let artistDataMap = artistData.map(artistName => 
    //console.log(artistName);
    return (
      <aside className="artist-section">
        <span>artistName</span>
        <button
          className="astbutton"
          onClick= function GetCardList() 
            fetch(
              `https://api.scryfall.com/cards/search?unique=prints&q=a:"$artistName"`
            )
              .then(response => 
                return response.json();
              )
              .then((cardResults) => 
                console.log(cardResults.has_more)
                if (cardResults.has_more === true) 
                fetch (`https://api.scryfall.com/cards/search?unique=prints&q=a:"$artistName"&page=2`)
                .then((responsepagetwo) => 
                  return responsepagetwo.json();
                )
                .then(cardResultsPageTwo => 
                  console.log(`First Results Page: $cardResults`)
                  console.log(`Second Results Page: $cardResultsPageTwo`)
                  setFullResults(cardResults.data.concat(cardResultsPageTwo.data))
                  console.log(`Full Results: $fullResults`)
                )
                
                setShowTheCards(
                  cardResults.data
                  .filter(( digital ) => digital === false)
                  .map(cardData => 
                    if (cardData.layout === "transform") 
                      return (
                        //TODO : Transform card code
                        <span>Transform Card (Needs special return)</span>
                      )
                    
                    else if (cardData.layout === "double_faced_token") 
                      return (
                        //TODO: Double Faced Token card code
                        <span>Double Faced Token (Needs special return)</span>
                      )
                    
                    else 
                      return (
                        <div className="card-object">
                          <span className="card-object-name">
                          cardData.name
                          </span>
                          <span className="card-object-set">
                          cardData.set_name
                          </span>
                          <img
                          className="card-object-img-sm"
                          alt=cardData.name
                          src=cardData.image_uris.small
                          />
                        </div>
                      )
                    
                  )
                )
              );
          
        >
          Show Cards
        </button>

      </aside>
    );
  );

  return (
    <aside>
      <aside className="artist-group">
      artistDataMap
      </aside>
      <aside className="card-wrapper">
      showTheCards
      </aside>
    </aside>
  );
;

export default App;

CodesAndBox:https://codesandbox.io/embed/compassionate-satoshi-iq3nc?fontsize=14

【问题讨论】:

每次点击都会加载结果,给我们展示一个重现的例子。 抱歉,累了 - 单击 Jeff A. Menges 旁边的按钮并检查控制台日志。 我无法在 Jeff A. Menges 的点击上重现。 您在设置状态后立即访问 fullResults,检查渲染中的 fullresults 它应该具有最新值。 您的 console.log 语句首先调用然后 setState。 useEffect(() =&gt; console.log(fullResults); setFullResults(); ); 【参考方案1】:

您可以尝试重构代码,例如 onClick 处理程序有一个合成事件。将此事件侦听器添加为类的一部分。使用箭头函数,这样您就不需要在构造函数中绑定此函数处理程序。获取数据后,尝试将状态设置为结果,并使用该状态在 render 方法中渲染 html 标记。当我运行这段代码时,我还在控制台中看到了一个错误,即子元素需要 key 属性。我已经看到您在渲染方法中使用 Array.prototype.map ,但是当您返回其中的 span 元素时,尝试添加一个关键属性,以便当 React diffing 算法遇到一个新元素时,它会降低检查某些节点的时间复杂度这个关键属性。

【讨论】:

【参考方案2】:
useEffect(() => 
   // call the functions which depend on fullResults here
   setFullResults();
, [fullResults])

// 现在它将检查 fullResults 是否发生了变化,如果发生变化,则检查 useEffect 内部的函数是否取决于 fullResults

【讨论】:

以上是关于React Hooks:useState with onClick 仅更新第二次单击按钮?的主要内容,如果未能解决你的问题,请参考以下文章

React hooks的useState原理

React Hooks - 使用 useState 与仅使用变量

React Hooks --- useState 和 useEffect

react hooks useState 赋值优化解决方案

Firebase 和 React Hooks(useState 和 useEffect)

react源码debugger-各个hooks的逻辑实现(useState和useEffect)