Skip to content

Commit 680746e

Browse files
committed
perf: Optimize BinaryDigit
Unrolls the digit into a static four or six dot column. Combined with an updated `useBinaryTime` hook which preserves object references at the bit level (where possible), now only the dots which change with the new time get rerendered. As a result, typical full render times are below 5ms. When a time update affects multiple digits render times can occasionally climb to ~12ms.
1 parent 7217a11 commit 680746e

File tree

2 files changed

+53
-17
lines changed

2 files changed

+53
-17
lines changed

src/components/BinaryDigit.tsx

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// License, v. 2.0. If a copy of the MPL was not distributed with this
55
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
66

7-
import {StyleSheet, Text, View} from 'react-native';
7+
import {StyleSheet, View} from 'react-native';
88

99
import BinaryDot from './BinaryDot';
1010
import React from 'react';
@@ -25,21 +25,48 @@ const DEFAULTS = {
2525

2626
const BinaryDigit: React.FC<BinaryDigitProps> = args => {
2727
const props = {...DEFAULTS, ...args};
28+
if (props.digit.bits.length === 4) {
29+
return <FourDigit {...props} />;
30+
} else if (props.digit.bits.length === 6) {
31+
return <SixDigit {...props} />;
32+
} else {
33+
throw new Error(`Invalid digit length: ${props.digit.bits.length}`);
34+
}
35+
};
36+
37+
const FourDigit: React.FC<BinaryDigitProps> = props => {
38+
const settings = {
39+
brightness: props.brightness,
40+
roundness: props.roundness,
41+
showHints: props.showHints,
42+
};
43+
return (
44+
<View style={styles.pair}>
45+
<View style={styles.digit}>
46+
<BinaryDot bit={props.digit.bits[0]} {...settings} />
47+
<BinaryDot bit={props.digit.bits[1]} {...settings} />
48+
<BinaryDot bit={props.digit.bits[2]} {...settings} />
49+
<BinaryDot bit={props.digit.bits[3]} {...settings} />
50+
</View>
51+
</View>
52+
);
53+
};
54+
55+
const SixDigit: React.FC<BinaryDigitProps> = props => {
56+
const settings = {
57+
brightness: props.brightness,
58+
roundness: props.roundness,
59+
showHints: props.showHints,
60+
};
2861
return (
2962
<View style={styles.pair}>
3063
<View style={styles.digit}>
31-
{props.digit.bits.map((bit, idx) => (
32-
<BinaryDot
33-
key={idx}
34-
bit={bit}
35-
brightness={props.brightness}
36-
roundness={props.roundness}
37-
showHints={props.showHints}
38-
/>
39-
))}
40-
{props.showHints && (
41-
<Text style={styles.hint}>{props.digit.value}</Text>
42-
)}
64+
<BinaryDot bit={props.digit.bits[0]} {...settings} />
65+
<BinaryDot bit={props.digit.bits[1]} {...settings} />
66+
<BinaryDot bit={props.digit.bits[2]} {...settings} />
67+
<BinaryDot bit={props.digit.bits[3]} {...settings} />
68+
<BinaryDot bit={props.digit.bits[4]} {...settings} />
69+
<BinaryDot bit={props.digit.bits[5]} {...settings} />
4370
</View>
4471
</View>
4572
);

src/utils/useBinaryTime.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { useState, useEffect } from "react";
2-
import { BinaryTimeMode, asBinaryTime } from "./binaryTime";
3-
import { useTime } from "./useTime";
1+
import {useState, useEffect} from 'react';
2+
import {BinaryTimeMode, asBinaryTime} from './binaryTime';
3+
import {useTime} from './useTime';
4+
import isEqual from 'lodash/isEqual';
45

56
export function useBinaryTime(
67
mode: BinaryTimeMode = BinaryTimeMode.SINGLE_DIGITS,
@@ -14,8 +15,16 @@ export function useBinaryTime(
1415
prev.map((digit, idx) => {
1516
if (digit.value === newDigits[idx].value) {
1617
return digit;
18+
} else {
19+
// Where possible, preserve object references on a per-bit basis.
20+
return {
21+
value: newDigits[idx].value,
22+
bits: digit.bits.map((bit, bitIdx) => {
23+
const newBit = newDigits[idx].bits[bitIdx];
24+
return isEqual(bit, newBit) ? bit : newBit;
25+
}),
26+
};
1727
}
18-
return newDigits[idx];
1928
}),
2029
);
2130
}, [time, mode]);

0 commit comments

Comments
 (0)