skip to Main Content

So I am currently in my final stages of finishing a webapp in React.
In this stage I am looking for performance issues and I am trying to optimize the performance.

So I have 3 components:

RulePage, RuleList (Contains a list of OrderRules), OrderRule

When I select (highlight) an OrderRule, it gets different CSS and the id of the OrderRule is being sent to the page through the list, because the page must send requests for a selected orderRule, so it needs the ID.

However, when I select an orderRule, every item in the OrderRuleList rerenders and that causes some bad performance on mobile devices.

I tried some things with useMemo, but unfortunately I was not able to fix the performance issue.

Here’s my code, simplified:

Page:

const [rules, setRules] = useState([]);
const [selected, setSelected] = useState(null);

function setSelectedRule(oid){ setSelected(oid); }

return (
    {rules && <OrderRuleList selected={selected} setSelectedRule={setSelectedRule} rules={rules} {...aLotOfProps}/>}
);

List:

function setSelectedRule(oid){
    props.setSelectedRule(oid);
}

return (
    {props.rules.map((rule) => <OrderRule selected={props.selected} data={rule} setSelectedRule={setSelectedRule} {...moreProps}/>)}
);

ListItem:

const [selected, setSelected] = useState(props.selected === props.data?.Oid);
const rule = props.data;

return (
    <div onClick={() => props.setSelectedRule(rule?.Oid)}>
        {...otherStuff}
    </div>
);

Does anyone have any tips for optimization? Thank you in advance.

2

Answers


  1. Chosen as BEST ANSWER

    Memoing like @jagmitg did, didn't solve the case, but I found a solution based on his suggestions that did work:

    const MemoRule = React.memo(OrderRule, (prevProps, nextProps) => 
    {
        return !(prevProps.selected === prevProps.rule?.Oid || nextProps.selected === nextProps.rule?.Oid);
    });
        
    export default MemoRule;
    

    This causes a check: when an orderrule was selected before and not anymore, it gets rerenderd OR when an orderrule is being selected and was not selected before, it gets rerenderd.


  2. One way to optimise the performance is to remove the local state from OrderRule component.

    Heres an example:

    Page:

    const [rules, setRules] = useState([]);
    const [selected, setSelected] = useState(null);
    
    function setSelectedRule(oid) { 
        setSelected(oid); 
    }
    
    return (
        {rules && <OrderRuleList selected={selected} setSelectedRule={setSelectedRule} rules={rules} {...aLotOfProps}/>}
    );
    

    List:

    function setSelectedRule(oid) {
        props.setSelectedRule(oid);
    }
    
    return (
        {props.rules.map((rule) => <OrderRule selected={props.selected === rule.Oid} data={rule} setSelectedRule={setSelectedRule} {...moreProps}/>)}
    );
    

    ListItem:

    const rule = props.data;
    
    return (
        <div onClick={() => props.setSelectedRule(rule?.Oid)} className={props.selected ? 'selected' : ''}>
            {...otherStuff}
        </div>
    );
    

    The OrderRuleList checks if the current rule is selected one while mapping over the rules. The value is passed down to the OrderRule component.

    OrderRule no longer has local state. Instead, the 'selected' prop that it receives from OrderRuleList is directly used to determine if it should have the ‘selected’ class.

    Lastly, i would suggest implementing React.memo to prevent unnecessary renders. If you have a lot of complex props, consider using useMemo or useCallback hooks for those props.

    EDIT: Example of how to use memo

    Please note that i dont have access to your full code base so this example is from what i think it should be.

    Page:

    import React, { useState } from 'react';
    import OrderRuleList from './OrderRuleList';
    
    export default function RulePage(props) {
        const [rules, setRules] = useState([]);
        const [selected, setSelected] = useState(null);
    
        function setSelectedRule(oid) { 
            setSelected(oid); 
        }
    
        return (
            {rules && <OrderRuleList selected={selected} setSelectedRule={setSelectedRule} rules={rules} {...props}/>}
        );
    }
    

    List:

    import React from 'react';
    import OrderRule from './OrderRule';
    
    export default function OrderRuleList(props) {
        const setSelectedRule = (oid) => {
            props.setSelectedRule(oid);
        }
    
        return (
            {props.rules.map((rule) => <OrderRule key={rule.Oid} selected={props.selected === rule.Oid} data={rule} setSelectedRule={setSelectedRule} {...props}/>)}
        );
    }
    

    ListItem:

    import React from 'react';
    
    function OrderRule(props) {
        const rule = props.data;
    
        return (
            <div onClick={() => props.setSelectedRule(rule?.Oid)} className={props.selected ? 'selected' : ''}>
                {...props.otherStuff}
            </div>
        );
    }
    
    export default React.memo(OrderRule);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search