Search code examples
reactjsimmutabilityderivedreact-component

How to pass a derived object to another component without triggering unecessary re-rendering?


I've got a component like the one below:

class MyComponent extends React.PureComponent {

    constructor() {
        super();

        this.state = {
            range: {
                start: 1000,
                length: 5000,
            },
        }
    }

    render() {
        const range = this.state.range;

        return (
            <div>
                <ThirdPartyComponent
                    interval={{
                        begin: range.start,
                        end: range.start + range.length,
                    }}
                />
            </div>
        );
    }

}

Basically it has a "range" state object which is transformed and then passed to a third-party component. The code as it is works but the issue is that the interval is always a new object, even when the range doesn't change, which means ThirdPartyComponent re-render even when it doesn't need to.

Usually I solve this by caching the derived object (in this case "interval") and updating it only when the range changes. It works but it leads to a lot of boiler plate code, and it needs to be done for each similar property.

So I'm wondering what would be the proper way to do that in React? Or maybe is there some lib I could use that would handle this for me?


Solution

  • I found the answer to what I want to do: it's called a "memoized selector" apparently and there's a package for it here: https://www.npmjs.com/package/reselect

    With this lib I can do this:

    import { createSelector } from 'reselect'
    
    const getRange = state => state.range;
    
    const getInterval = createSelector(
        [ getRange ], range => {
            return {
                begin: range.start,
                end: range.start + range.length,
            };
        }
    })
    

    And the interval will be updated only if the range is updated.