jjzjj

javascript - React useReducer Hook 触发两次/如何将 props 传递给 reducer?

coder 2024-07-22 原文

前言/描述

我正在尝试将 React 的新 Hook 功能用于我正在构建的电子商务网站,但在解决我的购物车组件中的错误时遇到了问题。

我认为在讨论前先说明我正在尝试通过使用多个 Context 组件来保持全局状态模块化这一事实是相关的。我有一个单独的上下文组件用于我提供的项目类型,还有一个单独的上下文组件用于一个人的购物车中的项目。

问题

我遇到的问题是,当我发送一个将组件添加到我的购物车的操作时,reducer 将运行两次,就好像我将商品添加到我的购物车两次一样。但仅当它最初被渲染时,或出于奇怪的原因,例如显示设置为 hidden 然后返回到 block 或更改 z- index 和其他可能的类似更改。

我知道这有点冗长,但这是一个相当挑剔的问题,所以我创建了两个代码笔来展示这个问题:

full example

minimum example

您会看到我包含了一个按钮来切换组件的显示。这将有助于展示 css 与问题的相关性。

最后请在代码笔中监控控制台,这将显示所有按钮点击以及每个 reducer 的哪一部分已经运行。这些问题在 full example 中最为明显,但控制台语句显示问题也存在于 minimum example 中.

问题领域

我已经确定问题与我正在使用 useContext Hook 的状态来获取项目列表这一事实有关。调用一个函数来为我的 useReducer 钩子(Hook)生成 reducer,但只有在使用不同的钩子(Hook)时才会出现,也就是我可以使用一个不会像 hook is 和 not 一样重新评估的函数有问题,但我还需要我以前的上下文中的信息,这样解决方法并不能真正解决我的问题。

相关链接

我已确定问题不是 HTML 问题,因此我不会包含指向我尝试过的 HTML 修复的链接。该问题虽然是由 css 触发的,但并非根植于 css,因此我也不会包含 css 链接。

useReducer Action dispatched twice

最佳答案

如您所述,原因与 related answer 相同你链接到我的。每当 Provider 重新渲染时,您都会重新创建 reducer,因此在某些情况下,React 会执行 reducer 以确定它是否需要重新渲染 Provider 如果确实需要重新渲染,它会检测到 reducer 已更改,因此 React 需要执行新的 reducer 并使用它产生的新状态,而不是以前版本的 reducer 返回的状态。

当由于对 props 或上下文或其他状态的依赖而不能将 reducer 移出功能组件时,解决方案是使用 useCallback 内存你的 reducer ,以便您仅在其依赖项发生变化时创建一个新的 reducer (例如,在您的情况下为 productsList)。

另一件要记住的事情是,您不必过分担心您的 reducer 会为一次分派(dispatch)执行两次。 React 所做的假设是 reducers 通常会足够快(它们不能做任何有副作用的事情,进行 API 调用等),值得在某些场景中需要重新执行它们的风险为了尽量避免不必要的重新渲染(如果在带有 reducer 的元素下面有一个大的元素层次结构,这可能比 reducer 昂贵得多)。

这是使用 useCallbackProvider 的修改版本:

const Context = React.createContext();
const Provider = props => {
  const memoizedReducer = React.useCallback(createReducer(productsList), [productsList])
  const [state, dispatch] = React.useReducer(memoizedReducer, []);

  return (
    <Context.Provider value={{ state, dispatch }}>
      {props.children}
    </Context.Provider>
  );
}

这是您的代码笔的修改版本:https://codepen.io/anon/pen/xBdVMp?editors=0011

这里有几个与 useCallback 相关的答案,如果您不熟悉如何使用此 Hook ,它们可能会有所帮助:

关于javascript - React useReducer Hook 触发两次/如何将 props 传递给 reducer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55055793/

有关javascript - React useReducer Hook 触发两次/如何将 props 传递给 reducer?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

随机推荐