jjzjj

javascript - Redux - 了解返回函数的高级 mapStateToProps

coder 2024-07-30 原文

我试图了解 mapStateToProps 返回函数时的机制。

所以我找不到太多的文档,除了 Redux 文档的一个简短摘录,它通过返回一个函数提前说明情况,每个实例都会得到自己的内存 mapStateToProps 和另一个用户说这是一种防止 mapStateToProps 被要求更改任何父属性。

所以这对于列表项来说似乎很棒,我不想为不影响项目的任何更改重新呈现大型项目列表。

所以让我感到困惑的部分是 mapStateToProps 不会因任何父属性更改而被调用,这是否意味着为了重新呈现单个列表“Item”,它需要成为它的智能连接组件获取它关心的更改并重新渲染?或者这是否意味着它永远不会为这个特定的 Item 实例重新呈现?

更新:

想澄清一下,我正在专门谈论 mapStateProps 的工厂功能版本。

这是我正在谈论的功能,摘自 React-Redux 文档:

注意:在需要对渲染性能进行更多控制的高级场景中,mapStateToProps() 也可以返回一个函数。在这种情况下,该函数将用作特定组件实例的 mapStateToProps() 。这允许您进行每个实例的内存。您可以引用#279 及其添加的测试以获取更多详细信息。大多数应用永远不需要这个。

摘自这篇文章的段落:

https://medium.com/@cvetanov/redux-mapstatetoprops-optimization-5880078a8a7a

如果 redux 收到一个返回函数的实现,它会执行一个闭包来包装组件自己的 props,因此每次组件更改它从父组件接收到的 props 时,都会绕过 mapStateToProps 的调用。它创建了一个所谓的 purePropsSelector。可以在此处查看这是如何完成的。

更新 2:

对,我正在调查提到跳过的文章,它似乎是当你将自己的 Prop 包裹在一个闭包中并返回一个只使用状态的函数时。因此,当每个“已连接”子项的父属性更改时,它可以防止调用 mapStateToProps。

这是摘 self 在上面阅读的那篇媒体文章:

function mapStateToPropsFactory(initialState, ownProps) {
  // a closure for ownProps is created
  // this factory is not invoked everytime the component
  // changes it's props
  return function mapStateToProps(state) {
    return {
      blogs:
        state.blogs.filter(blog => blog.author === ownProps.user)
    };
  };
}
export default connect(mapStateToPropsFactory)(MyBlogs);

最佳答案

如果状态发生变化,每个 mapStateToProps 函数都会被调用。 redux 中没有包含阻止调用 mapStateToProps 的机制。

From the docs for connect():

mapStateToProps(state, [ownProps]): stateProps] (Function): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, mapStateToProps will be called.

您想要防止(通常通过使用选择器)发生在 mapStateToProps 内部的昂贵计算将在每次状态更新时重复,即使它们产生相同的结果。

Or does that mean it will never re-render for this particular Item instance?

如果连接组件收到的任何 Prop 发生变化,它将照常重新渲染。重点是防止 mapStateToProps 进行昂贵的计算。 mapStateToProps 是愚蠢的。它进行计算并将它们作为 Prop 传递给连接的组件。然后该组件检查 Prop 是否与以前的 Prop 不同,并决定基于此重新渲染。

考虑这个使用选择器 getVisibleTodosmapStateToProps 函数:

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

选择器会记住调用的结果,只要输入参数不变,就会在后续调用中简单地返回该结果。本例中的选择器仅从 redux 状态获取输入。只要 state.todosstate.visibilityFilter 不改变,它就可以使用上次调用的内存结果,不需要重新计算。

现在考虑另一个例子:

const TodoList = ({id, todos}) => (
  <ul id={id}>
    {todos.map(/* ... */)}
  </ul>
);

const mapStateToProps = (state, props) => {
  return {
    todos: getVisibleTodos(state, props)
  }
}

export default connect(mapStateToProps)(TodoList);

这次选择器另外将组件自己的属性作为输入。这是有问题的,因为如果我们使用连接的 TodoList 的两个实例并将其呈现为

<TodoList id="list1" />
<TodoList id="list2" />

这将导致 mapStateToProps 在状态更新时被调用两次,每个 TodoList 实例调用一次。并且两次它都会收到不同的 Prop 。一次使用 {id: 'list1'},第二次使用 {id: 'list2'}。但是这两个组件共享相同的选择器。这将导致选择器重新计算,即使每个单独的 TodoListtodos 没有改变。现在自己返回一个函数的mapStateToProps函数就派上用场了:

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos() // this creates a new selector function
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props)
    }
  }
  return mapStateToProps
}

这为 TodoList 的每个实例创建了一个单独的 mapStateToProps 函数,它有自己的选择器,因此它会单独记住每个实例的属性,并且只有在以下情况下才会重新计算它是为更改而创建的实例的 Prop 。这将解决前面示例中的问题。

所以 tl;dr;:当 mapStateToProps 中的选择器将连接组件的自己的 props 作为参数时,您需要使用 mapStateToProps 作为工厂以允许用于每个实例的内存。

您可以在 Comuting Derived Data 下找到更详细的示例说明在 redux 文档中。

关于javascript - Redux - 了解返回函数的高级 mapStateToProps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50006884/

有关javascript - Redux - 了解返回函数的高级 mapStateToProps的更多相关文章

  1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  5. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  6. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  7. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  8. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  9. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  10. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

随机推荐