简体   繁体   中英

React.memo Not Preventing Re-renders of Stateless Functional Child Component that Takes In No Props

I've got a stateless functional component (see Title below) that uses React-Reveal to display some simple heading elements on render. In addition to having no internal state, Title also doesn't receive any props from its parent component ( GameHeader ). But for some reason, Title still keeps getting re-rendered whenever I update the overall application state from another, unrelated component elsewhere in the tree and this is causing the React-Reveal animations to run every single time some unrelated app state changes.

// GameHeader.js
 
import React from 'react';
import Title from './Title';
import Options from './Options';
 
const GameHeader = () => {
    return (
        <div>
            <Title />
            <Options />
        </div>
    );
}
 
export default GameHeader;
 
 
// Title.js --> this component needs to stop re-rendering so much because it contains entrance animations
 
import React from 'react';
import { Typography } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import Zoom from 'react-reveal/Zoom';
import Slide from 'react-reveal/Slide';
import Flip from 'react-reveal/Flip';
 
const Title = () => {
    console.log("Title rendering");
    const theme = useTheme();
 
    return (
        <>
            <Typography variant="subtitle1" color="primary">
                <Slide left>Sample</Slide>
            </Typography>
            <Typography variant="h1" style={{ color: `${theme.palette.indigo.main}` }}>
                <Flip delay={800} duration={600} cascade>App</Flip>
            </Typography>
            <Typography variant="h2" style={{ color: `${theme.palette.orange.dark}` }}>
                <Zoom delay={1100} cascade>Title</Zoom>
            </Typography>
        </>
    );
}
 
export default React.memo(Title);

I've tried wrapping Title in React.memo or converting it to a PureComponent, but to no avail -- it still keeps needlessly re-rendering and re-triggering its animations. I am using hooks + the Context API (w/ useReducer & dispatch) to update my application state elsewhere in the app, but I am not consuming any of that state directly in GameHeader or Title .

I suspect that because React.memo/PureComponent only do a shallow compare between state & props, that maybe there is a phantom prop or something that is non-equivalent between renders that is still getting passed into Title somehow?? But I don't know why that would be, or how to confirm or address that. Or maybe I am just using React.memo incorrectly?

I understand that children re-rendering on parent state changes is just how React works, but I need a way to prevent my transitions from firing after unrelated state changes and React.memo doesn't seem to be doing the trick. Any thoughts?

Tracing it back up the tree got me to the solution. It turns out that the Material UI styled component wrappers I was using around GameHeader were causing GameHeader to remount every time, when I removed the styled component wrappers, GameHeader stopped remounting. Same thing with Title , though in the example I showed above, I had already removed the styled component wrapper from around that one.

These MUI styled component definitions were sitting inside my parent functional components (because they were making use of useTheme), so what I ended up doing was moving those MUI styled component definitions outside of the parent functional components (after the export default statement) and that, for whatever reason, completely resolved the issue.

Thanks @Jayce444 for pointing me in the right direction!

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