Skip to content

Instantly share code, notes, and snippets.

@scottmas
Last active December 5, 2019 02:05
Show Gist options
  • Save scottmas/b97c6e5ac177bc87c0730413d4e661a4 to your computer and use it in GitHub Desktop.
Save scottmas/b97c6e5ac177bc87c0730413d4e661a4 to your computer and use it in GitHub Desktop.
Side effects in render
function superExpensiveMapFn(num) {
//do something synchronous and very expensive, compounded by the fact that the array it operates on is very large
return num;
}
function useExpensiveDerivation(largePushOnlyArray: number[]){
const prevPushOnlyArray = useRef(largePushOnlyArray);
const derivedArray = useRef(useMemo(() => largePushOnlyArray.map(superExpensiveMapFn), []))
if(largePushOnlyArray.length > prevPushOnlyArray.current.length){
// When the array length changes, only operate the map function on the newly added subset
derivedArray.current = derivedArray.current.slice(prevPushOnlyArray.current.length).map(superExpensiveMapFn)
}
return derivedArray.current
}
function App(){
const [largePushOnlyArray, setPushOnlyArray] = useState([]);
const derivedArray = useExpensiveDerivation(largePushOnlyArray);
return <div>
{derivedArray.map(num => <div>{num}</div>)}
<button onClick={() => {
setPushOnlyArray(pushOnlyArray.concat(pushOnlyArray.length);
}}>
Increment
</button>
</div>
}
@scottmas
Copy link
Author

scottmas commented Dec 5, 2019

It's easy to not cause side effects if you simply create an additional state variable inside useExpensiveDerivation and update that new variable inside a useEffect block, but this causes an undesirable (and unnecessary) double render whenever a new value is pushed to pushOnlyArray - once for the change to pushOnlyArray and once for the change to the shadow state variable inside useExpensiveDerivation. Or maybe I'm missing a solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment