React.memo-为什么我的相等函数没有被调用?

时间:2019-11-22 14:23:26

标签: reactjs

我有一个父组件,该组件根据通过props接收的数组来呈现子级集合。

import React from 'react';
import PropTypes from 'prop-types';
import shortid from 'shortid';
import { Content } from 'components-lib';
import Child from '../Child';

const Parent = props => {
  const { items } = props;

  return (
    <Content layout='vflex' padding='s'>
      {items.map(parameter => (
        <Child parameter={parameter} key={shortid.generate()} />
      ))}
    </Content>
  );
};

Parent.propTypes = {
  items: PropTypes.array
};

export default Parent;

每次添加新的item时,所有子项都被重新渲染,而我试图避免这种情况,我不希望其他子项被重新渲染,我只想渲染最后一个已添加。

因此,我在孩子身上尝试了React.memo,我可能会通过code属性或类似的东西来进行比较。问题在于,永远不会调用相等函数。

import React from 'react';
import PropTypes from 'prop-types';
import { Content } from 'components-lib';

const areEqual = (prevProps, nextProps) => {
  console.log('passed here') // THIS IS NEVER LOGGED!!
}

const Child = props => {
  const { parameter } = props;
  return <Content>{parameter.code}</Content>;
};

Child.propTypes = {
  parameter: PropTypes.object
};

export default React.memo(Child, areEqual);

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

简而言之,这种行为的原因是由于React的工作方式。

React期望每个组件都有一个唯一的键,以便它可以跟踪并知道哪个是哪个。通过使用->having(function($exp, $qb) { $default_sum = $qb->func()->sum('video_is_default'); return $exp->lt($default_sum, 1); }) ,会创建一个新的键值,对该组件的引用也会更改,React认为它是一个全新的组件,需要重新渲染。

在您的情况下,如果父项中的道具发生任何变化,React都会重新渲染所有子项,因为与之前的渲染相比,所有子项的键都将有所不同。

Please reference this wonderful answer to this topic

希望这会有所帮助!

答案 1 :(得分:0)

我不了解您的库的其余部分,但是我做了一些更改,并且您的代码(大部分)似乎可以正常工作。因此,也许可以帮助您缩小原因范围。

https://codesandbox.io/s/cocky-sun-rid8o

答案 2 :(得分:0)

当在孩子身上包括一个标识性关键属性并使用React.memo时,出现意外渲染的另一种可能性(与这个特定问题无关,但我认为在此处包括仍然有用)。

我认为React只会在children道具上做一些区分。除此之外,children道具与其他任何属性都没有不同。因此,对于此代码,使用myList而非children会导致意外的渲染:

export default props => {
  return (
    <SomeComponent
     myLlist={
      props.something.map(
        item => (
          <SomeItem key={item.id}>
            {item.value}
          </SomeItem>
        )
      )
     }
    />
  )
}

// And then somewhere in the MyComponent source code:
...
{ myList } // Instead of { children }
...

此代码(如下)将不会:

export default props => {
  return (
    <SomeComponent
     children={
      props.something.map(
        item => (
          <SomeItem key={item.id}>
            {item.value}
          </SomeItem>
        )
      )
     }
    />
  )
}

该代码与隐式在children上指定MyComponent道具(ES Lint不会抱怨)完全相同:

export default props => {
  return (
    <SomeComponent>
    {props.something.map(
      item => (
        <SomeItem key={item.id}>
          {item.value}
        </SomeItem>
      )
    )}
    </SomeComponent>
  )
}