使用React钩子实现shouldComponentUpdate-仅渲染一次子项,但在props更改时进行DOM更改

时间:2020-02-02 15:49:39

标签: javascript reactjs react-hooks

我有一些使用shouldComponentUpdate处理React.Component的东西,想将其转换为使用React Hooks,但是我不确定是否有可能。

我有一个子组件,可以渲染非常昂贵的ChartingLibrary画布,因此我只想渲染一次Child react组件。

制图画布的内容取决于传递给子级的道具,因此必须使用传递给子级的道具调用ChartingLibrary上的某些api。

因此,当传递给子代的道具发生变化时,我需要在图表库中调用api,但是我不想刷新“子代”组件。

这与React类一起使用,如下所示:


    const Parent = () => {
        <Child/>
    }

    export class Child extends React.Component {
        shouldComponentUpdate (nextProps, nextState) {
            ChartingLibrary.init()
            ChartingLibrary.doStuffWithProps(nextProps.data)
            return false
        }
    }

React.memo有问题:

与React.Component版本最接近的是React.Memo,但是我无法从isSame函数内部访问ChartingLibrary。反应React.Component版本使我能够从组件内部访问ChartingLibrary,而React.memo只能从组件外部进行。


    const Parent = () => {
        <Child/>
    }

    const Child = (props) => {
        ChartingLibrary.init()
        ChartingLibrary.doStuffWithProps(props) 
    }
    const ChildMemo = React.memo(Child, function isSame (prevProps, props) {
        ChartingLibrary.doStuffWithProps(props)
        return true
    })

有更好的方法吗?我想用钩子做些什么吗?

2 个答案:

答案 0 :(得分:1)

您猜对了,我猜对了。 React.memo是实现所需内容的方法。

function MyComponent(props) {
  /* render using props */
}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(MyComponent, areEqual);

如文档中所述:

与类组件上的shouldComponentUpdate()方法不同, 如果道具相等,则areEqual函数返回true;如果道具相等,则返回false。 道具不平等。这是与shouldComponentUpdate相反的。

希望这会对您有所帮助。

答案 1 :(得分:0)

谢谢@Muhammad Zeeshan,我只需要在道具更改时为文本字段 (RN) 设置动画:

import React, { useEffect, useRef } from 'react';
import { Animated } from 'react-native';
const AnimatedView = props => {
  const animatedOpacity = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.sequence(
      [
        Animated.timing(animatedOpacity, {
          toValue: 0,
          duration: 500,
          useNativeDriver: true
        }),
        Animated.timing(animatedOpacity, {
          toValue: 1,
          duration: 0,
          useNativeDriver: true
        })
      ],
      { useNativeDriver: true }
    ).start();
  }, [props.children]);

  return (
    <Animated.Text
      style={{
        opacity: animatedOpacity
      }}
    >
      {props.children}
    </Animated.Text>
  );
};

const comparator = (prevProps, nextProps) => {
  if (prevProps.children !== nextProps.children) {
    return true;
  }
  return false;
};

export default React.memo(AnimatedView, comparator);