简体   繁体   中英

Implement shouldComponentUpdate with React hooks - Render child only once, but make DOM changes when props change

I have something working with a React.Component using shouldComponentUpdate, and want to convert it to use React Hooks, but I'm not sure it's even possible.

I have a child component that renders a very expensive ChartingLibrary canvas, so I only want to render the Child react component once.

The charting canvas content is dependent on props passed to the Child and certain apis on the ChartingLibrary have to be called with the props passed to the child.

So when the props passed to the child changes, I need to call apis on the Charting Library, but I don't want to refresh the Child component.

This is working with a React Class as follows:


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

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

React.memo is problematic:

The closest I can get to the React.Component version is with React.Memo, but I don't have access to the ChartingLibrary from inside the isSame function. React. The React.Component version gives me access to ChartingLibrary from inside the component whereas React.memo can only be done from outside the component.


    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
    })

Is there a better way? Is what I'm trying to do possible with hooks?

You are doing it the right way i guess. React.memo is the way you can achieve what you are looking for.

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);

As said in the documentation:

Unlike the shouldComponentUpdate() method on class components, the areEqual function returns true if the props are equal and false if the props are not equal. This is the inverse from shouldComponentUpdate.

Hope this will help you.

Thank you @Muhammad Zeeshan, I needed that to only animate a text field (RN) when the props changed:

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM