Skip to main content

shallowArrayEqualityCheck

Shallow equality check for arrays of primitive values. Compares array length and each element's value rather than array reference.

When to Use

Use when deriving arrays of primitives (strings, numbers, booleans):

Signature

typescript
function shallowArrayEqualityCheck(): (current: Immutable[]) => boolean
type Immutable = string | number | boolean | null | undefined | Function

Basic Usage

tsx
import { shallowArrayEqualityCheck } from '@react-facet/core'
 
const equalityCheck = shallowArrayEqualityCheck()
 
equalityCheck([0, 1, 2])
 
console.log(equalityCheck([0, 1, 2])) // true - same values
console.log(equalityCheck([0, 1, 2, 3])) // false - different length
console.log(equalityCheck([0, 1, 2, 3])) // true - same values again
console.log(equalityCheck([0, 1, 3])) // false - different value at index 2
console.log(equalityCheck([0, 1, 3])) // true

Usage with Facets

Filtering Arrays

tsx
import { useFacetMap, useFacetWrap, shallowArrayEqualityCheck } from '@react-facet/core'
 
const PlayerList = () => {
const playerIdsFacet = useFacetWrap([1, 2, 3, 4, 5])
const activeIdsFacet = useFacetWrap([2, 4])
 
const activePlayersFacet = useFacetMap(
(allIds, activeIds) => allIds.filter((id) => activeIds.includes(id)),
[],
[playerIdsFacet, activeIdsFacet],
shallowArrayEqualityCheck, // Prevents updates when filtered array hasn't changed
)
 
return <div>Active players</div>
}

Transforming Arrays

tsx
import { useFacetMap, useFacetWrap, shallowArrayEqualityCheck } from '@react-facet/core'
 
const TagDisplay = () => {
const tagsFacet = useFacetWrap(['minecraft', 'game', 'sandbox'])
 
const uppercaseTagsFacet = useFacetMap(
(tags) => tags.map((tag) => tag.toUpperCase()),
[],
[tagsFacet],
shallowArrayEqualityCheck,
)
 
return <div>Tags</div>
}

Deriving Array from Multiple Facets

tsx
import { useFacetMap, useFacetWrap, shallowArrayEqualityCheck } from '@react-facet/core'
 
const Scoreboard = () => {
const player1ScoreFacet = useFacetWrap(100)
const player2ScoreFacet = useFacetWrap(150)
const player3ScoreFacet = useFacetWrap(75)
 
const scoresFacet = useFacetMap(
(p1, p2, p3) => [p1, p2, p3],
[],
[player1ScoreFacet, player2ScoreFacet, player3ScoreFacet],
shallowArrayEqualityCheck,
)
 
return <div>Scores</div>
}

Nullable Variant

For cases where the entire array might be null or undefined, use nullableShallowArrayEqualityCheck:

tsx
import { nullableShallowArrayEqualityCheck } from '@react-facet/core'
 
const equalityCheck = nullableShallowArrayEqualityCheck()
 
equalityCheck(null)
console.log(equalityCheck(null)) // true - null === null ✅
 
console.log(equalityCheck([1, 2, 3])) // false - null → array ❌
 
console.log(equalityCheck([1, 2, 3])) // true - same array values ✅
 
console.log(equalityCheck(undefined)) // false - array → undefined ❌
tip

For arrays with nullable elements (like (string | null)[]), you don't need the nullable variant. Regular shallowArrayEqualityCheck handles null/undefined elements just fine using strict equality (===).

How It Works

The equality check:

  1. Compares array lengths
  2. Iterates through each element
  3. Compares primitive values using ===
  4. Returns false if any element differs
tsx
import { shallowArrayEqualityCheck } from '@react-facet/core'
 
const check = shallowArrayEqualityCheck()
 
check([1, 2, 3])
 
// Different array reference, but same values
console.log(check([1, 2, 3])) // true ✅
 
// Different values
console.log(check([1, 2, 4])) // false ❌
 
// Different length
console.log(check([1, 2])) // false ❌

Important Notes

Only Shallow Comparison

This check does not perform deep comparison for nested arrays or objects:

tsx
import { shallowArrayEqualityCheck } from '@react-facet/core'
 
// ❌ Won't work as expected for nested structures
const check = shallowArrayEqualityCheck()
 
const nested1 = [{ name: 'Steve' }]
const nested2 = [{ name: 'Steve' }] // Different object references
 
// @ts-expect-error - Type error: array contains objects, not primitives
check(nested1)
// @ts-expect-error - Type error: array contains objects, not primitives
console.log(check(nested2)) // false - object references differ

Note: TypeScript will catch this mistake - the equality check expects arrays of primitives (string | number | boolean | null | undefined).

For arrays of objects, use:

Order Matters

Unlike objects, array element order is significant:

tsx
import { shallowArrayEqualityCheck } from '@react-facet/core'
 
const check = shallowArrayEqualityCheck()
 
check([1, 2, 3])
 
// Same values, different order - NOT equal
console.log(check([3, 2, 1])) // false ❌

Empty Arrays

Empty arrays are considered equal:

tsx
import { shallowArrayEqualityCheck } from '@react-facet/core'
 
const check = shallowArrayEqualityCheck()
 
check([])
 
console.log(check([])) // true ✅

Common Patterns

Filter and Sort

tsx
import { useFacetMap, shallowArrayEqualityCheck } from '@react-facet/core'
const sortedActiveIdsFacet = useFacetMap(
(ids, activeFlag) => ids.filter((id) => activeFlag[id]).sort((a, b) => a - b),
[],
[idsFacet, activeFlagsFacet],
shallowArrayEqualityCheck,
)

Extract Property Values

tsx
import { useFacetMap, shallowArrayEqualityCheck } from '@react-facet/core'
const playerNamesFacet = useFacetMap(
(players) => players.map((p) => p.name),
[],
[playersFacet],
shallowArrayEqualityCheck,
)

Range Generation

tsx
import { useFacetMap, shallowArrayEqualityCheck } from '@react-facet/core'
const pageNumbersFacet = useFacetMap(
(totalPages) => Array.from({ length: totalPages }, (_, i) => i + 1),
[],
[totalPagesFacet],
shallowArrayEqualityCheck,
)

Combining Multiple Arrays

tsx
import { useFacetMap, shallowArrayEqualityCheck } from '@react-facet/core'
const allTagsFacet = useFacetMap(
(userTags, systemTags) => [...userTags, ...systemTags],
[],
[userTagsFacet, systemTagsFacet],
shallowArrayEqualityCheck,
)

Performance Considerations

The equality check iterates through all array elements, so performance is O(n) where n is the array length.

For large arrays:

  • Consider if you really need the equality check
  • Profile before optimizing
  • For very large arrays (1000+ elements), consider custom equality checks that sample elements

Good performance:

tsx
// ✅ Small to medium arrays (< 100 elements)
const tagsFacet = useFacetMap((data) => data.tags, [], [dataFacet], shallowArrayEqualityCheck)

See Also