A faster React.memo()
. Also includes the fastest correct shallow object comparison function.
import fastMemo from 'react-fast-memo'
const MemoizedComponent = fastMemo(function Component(props) {
return (
<div className={props.className}>
I don't re-render often.
</div>
)
})
The comparison function is also included:
import { fastCompare } from 'react-fast-memo'
// `fastCompare` is for general and correct nullable-objects comparison
console.log(fastCompare(
{ a: 1, b: undefined },
{ a: 1 },
))
An unsafe comparison function is also exported, fastCompareUnsafe
, but it should only be used when objects are guaranteed to have the same shape.
In least performant to most performant order. Each function is benchmarked for objects that are equal
and unequal
.
The full results here are for V8, and I have added partial results for JSC and SpiderMonkey after. Suprisingly, in JSC
the safe version is the fastest one.
Runnable benchmark code is in the ./benchmark
folder, and consist of comparing two 8-keys monomorphic objects together
in a 1,000,000 iteration loop, in two cases: equal values, and unequal values (one differing value). Results are in
milliseconds
// V8
{
"fbjs/lib/shallowEqual:equal:monomorphic": { t: 1339.67, stddev: 2.35},
"fbjs/lib/shallowEqual:unequal:monomorphic": { t: 1274.33, stddev: 7.58},
"fast-shallow-equal:equal:monomorphic": { t: 1228.33, stddev: 36.44},
"fast-shallow-equal:unequal:monomorphic": { t: 1174.33, stddev: 2.62},
"react:equal:monomorphic": { t: 1240, stddev: 1.41},
"react:unequal:monomorphic": { t: 1229.67, stddev: 4.71},
"fast-equals.shallowEqual:equal:monomorphic": { t: 1261.33, stddev: 42.67},
"fast-equals.shallowEqual:unequal:monomorphic": { t: 333.33, stddev: 2.05},
"shallowequal:equal:monomorphic": { t: 1153, stddev: 67.23 },
"shallowequal:unequal:monomorphic": { t: 1188, stddev: 29.06},
"romgrk-fastCompare:equal:monomorphic": { t: 859.67, stddev: 3.39},
"romgrk-fastCompare:unequal:monomorphic": { t: 769.33, stddev: 2.05},
"hughsk/shallow-equals:equal:monomorphic": { t: 592.33, stddev: 41.96},
"hughsk/shallow-equals:unequal:monomorphic": { t: 563.33, stddev: 4.18},
// This one is faster than our safe one, but it uses `===` for comparison
// instead of `Object.is`, it is therefore incorrect because `NaN !== NaN`
// due to the unsound semantics of `===` in float comparison.
"romgrk-fastCompareUnsafe:equal:monomorphic": { t: 515.67, stddev: 1.24},
"romgrk-fastCompareUnsafe:unequal:monomorphic": { t: 455.67, stddev: 7.31},
}
// JSC
{
"react:equal:monomorphic": { t: 401, stddev: 25.152865973217974 },
"react:unequal:monomorphic": { t: 415.33, stddev: 3.39934634239519 },
"romgrk-fastCompareUnsafe:equal:monomorphic": { t: 313.67, stddev: 30.26916289265731 },
"romgrk-fastCompareUnsafe:unequal:monomorphic": { t: 244.67, stddev: 3.8586123009300755 },
"hughsk/shallow-equals:equal:monomorphic": { t: 297, stddev: 14.236104336041748 },
"hughsk/shallow-equals:unequal:monomorphic": { t: 189.33, stddev: 2.0548046676563256 },
"romgrk-fastCompare:equal:monomorphic": { t: 199.67, stddev: 6.847546194724712 },
"romgrk-fastCompare:unequal:monomorphic": { t: 128.67, stddev: 1.247219128924647 },
}
// SpiderMonkey
{
"react:equal:monomorphic": { t: 975.33, stddev: 1.24721912892464 },
"react:unequal:monomorphic": { t: 1073, stddev: 13.49073756323204 },
"hughsk/shallow-equals:equal:monomorphic": { t: 661.33, stddev: 50.5459087255228 },
"hughsk/shallow-equals:unequal:monomorphic": { t: 509, stddev: 22.01514630127782 },
"romgrk-fastCompare:equal:monomorphic": { t: 506.33, stddev: 3.3993463423951 },
"romgrk-fastCompare:unequal:monomorphic": { t: 503.67, stddev: 3.681787005729087 },
"romgrk-fastCompareUnsafe:equal:monomorphic": { t: 468.33, stddev: 6.18241233033046 },
"romgrk-fastCompareUnsafe:unequal:monomorphic": { t: 466.67, stddev: 3.09120616516523 },
}