reactjs 为什么我的等式函数没有被调用?

sczxawaw  于 2022-11-04  发布在  React
关注(0)|答案(4)|浏览(146)

我有一个父组件,它基于通过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);

知道为什么吗?

c3frrgcw

c3frrgcw1#

简而言之,这种行为的原因是由于React的工作方式。
React期望每个组件都有一个唯一的键,这样它就可以跟踪并知道哪个是哪个。通过使用shortid.generate(),键的新值被创建,对组件的引用发生变化,React认为这是一个全新的组件,需要重新呈现。
在您的示例中,在父对象中的任何道具更改时,React将重新渲染所有子对象,因为与上一次渲染相比,所有子对象的关键点都将不同。
Please reference this wonderful answer to this topic
希望这对你有帮助!

drkbr07n

drkbr07n2#

我也遇到了同样的问题,解决方案原来只是一个新手的错误。我张贴这只是以防万一,如果有人犯了同样的错误。
子组件必须位于父组件之外。因此,请不要:

function App() {
  const [strVar, setStrVar] = useState("My state str");

  const MyChild = React.memo(() => {
    return (
      <Text>
        {strVar}
      </Text>
    )
  }, (prevProps, nextProps) => {
      console.log("Hello"); //Never called
  });

  return (
    <MyChild/>
  )
}

这样做:

const MyChild = React.memo(({strVar}) => {
  return (
    <Text>
      {strVar}
    </Text>
  )
}, (prevProps, nextProps) => {
   console.log("Hello");
});

function App() {
  const [strVar, setStrVar] = useState("My state str");

  return (
    <MyChild strVar = {strVar}/>
  )
}
v7pvogib

v7pvogib3#

另一种意外呈现的可能性是,在子对象上包含一个标识键属性,并使用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>
        )
      )
     }
    />
  )
}

该代码与在MyComponent上隐式指定children属性完全相同(只是ES Lint没有抱怨):

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

4jb9z9bj4#

我不知道你的库的其余部分,但我做了一些修改,你的代码和(大部分)似乎工作。所以,也许,它可以帮助你缩小原因。
https://codesandbox.io/s/cocky-sun-rid8o

相关问题