physicsboy
physicsboy

Reputation: 6326

Reducing re-renders in React - Not going as expected

I am attempting to clean up my app and reduce the amount of re-renders that occur by using the React.memo feature, however I am struggling to understand fully why my page/component is re-rendering the amount of times it is. I believe it is down to my Redux usage and the different reducer steps that hit (fire, success, error).

App.jsx (pseudocode)

console.log("App");
return <div>
    <Switch>
       ...
       <Route render={Home} />
       ...
    </Switch>
</div>

export default App;

Home.jsx

const Home = () => {
   console.log("Home");
   return (
        <div>
          <DashboardBill/>
        </div>
    )
}

export default Home;

Dashboard.jsx

const Dashboard = () => {
    console.log("Dashboard");
    return <div>
        <MyBill/>
    </div>
}

export default memo(Dashboard);

MyBill.jsx

const mapStateToProps = ({billData}) => ({
    billData
});

const mapDispatchToProps = (dispatch) => ({
    loadData: () => dispatch(loadBillData)
});

const MyBill = ({billData, loadData}) => {
    console.log("MyBill");
    const [manipulatedData, setManipulatedData] = useState({});

    useEffect(() => {
        !billData && loadData();
    }, []);

    useEffect(() => {
       billData && setManipulatedData(someUtil.manipulate(billData));
    }, [billData]);

    return <div>{manipulatedData}</div>;
}

export default connect(mapStateToProps, mapDispatchToProps)(memo(MyBill));

The dispatch event ends up in a reducer that has the usual trigger, success and error cases to set the data within the Redux store etc.

When I load the page I am getting the following logging:

enter image description here

There are a few more dispatch events within the main App.jsx going on, but only a couple so that could account for the extra App mentions in the logs.

Can somebody attempt to explain what is going on here and why my memo() usages aren't doing what I am expecting?

Note: I am importing memo like import React, {memo, useEffect} from 'react';

Also, how would things be affected if MyBill were to have children that themselves made Redux store changes?

Upvotes: 0

Views: 37

Answers (1)

Antonin Riche
Antonin Riche

Reputation: 578

As I understand react.memo, render will be optimized if you use the component many times with the same props.
However, in your example, mapDispatchToProps provide a new function reference for loadData on every render. So your component is never rendering with the same props.

I guess you can optimize one rendering using useMemo hook

const MyBill = ({billData, loadData}) => {
    const manipulatedData = useMemo(() => billData ? someUtil.manipulate(billData) : {}, [billData]);

    useEffect(() => {
        !billData && loadData();
    }, []);

    return <div>{manipulatedData}</div>;
}

Upvotes: 1

Related Questions