Skip to content

Commit dd09e50

Browse files
committed
optimize useParticipantProperty rendering
1 parent 0925019 commit dd09e50

File tree

2 files changed

+83
-40
lines changed

2 files changed

+83
-40
lines changed

src/DailyParticipants.tsx

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,12 @@ import {
77
DailyWaitingParticipant,
88
} from '@daily-co/daily-js';
99
import React, { useCallback, useEffect, useState } from 'react';
10-
import {
11-
atom,
12-
atomFamily,
13-
selector,
14-
selectorFamily,
15-
useRecoilCallback,
16-
} from 'recoil';
10+
import { atom, atomFamily, selector, useRecoilCallback } from 'recoil';
1711

1812
import { useDaily } from './hooks/useDaily';
1913
import { useDailyEvent } from './hooks/useDailyEvent';
2014
import { useThrottledDailyEvent } from './hooks/useThrottledDailyEvent';
2115
import { RECOIL_PREFIX } from './lib/constants';
22-
import type { Paths } from './types/paths';
23-
import { resolveParticipantPaths } from './utils/resolveParticipantPaths';
2416

2517
/**
2618
* Extends DailyParticipant with convenient additional properties.
@@ -29,11 +21,6 @@ export interface ExtendedDailyParticipant extends DailyParticipant {
2921
last_active?: Date;
3022
}
3123

32-
type PropertyType = {
33-
id: string;
34-
properties: Paths<ExtendedDailyParticipant>[];
35-
};
36-
3724
/**
3825
* Stores the most recent peerId as reported from [active-speaker-change](https://docs.daily.co/reference/daily-js/events/meeting-events#active-speaker-change) event.
3926
*/
@@ -76,20 +63,6 @@ export const participantsState = selector<ExtendedDailyParticipant[]>({
7663
},
7764
});
7865

79-
/**
80-
* Holds each individual participant's property.
81-
*/
82-
export const participantPropertyState = selectorFamily<any, PropertyType>({
83-
key: RECOIL_PREFIX + 'participant-property',
84-
get:
85-
({ id, properties }) =>
86-
({ get }) => {
87-
const participant = get(participantState(id));
88-
89-
return resolveParticipantPaths(participant, properties);
90-
},
91-
});
92-
9366
/**
9467
* Holds all participants in the waiting room.
9568
*/

src/hooks/useParticipantProperty.ts

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
1-
import { useRecoilValue } from 'recoil';
1+
import deepEqual from 'fast-deep-equal';
2+
import { useCallback, useEffect, useState } from 'react';
3+
import {
4+
selectorFamily,
5+
useRecoilCallback,
6+
useRecoilTransactionObserver_UNSTABLE,
7+
} from 'recoil';
28

39
import {
410
ExtendedDailyParticipant,
5-
participantPropertyState,
11+
participantState,
612
} from '../DailyParticipants';
13+
import { RECOIL_PREFIX } from '../lib/constants';
714
import type { NumericKeys } from '../types/NumericKeys';
815
import type { Paths } from '../types/paths';
916
import type { PathValue } from '../types/pathValue';
17+
import { resolveParticipantPaths } from '../utils/resolveParticipantPaths';
18+
19+
type PropertyType = {
20+
id: string;
21+
properties: Paths<ExtendedDailyParticipant>[];
22+
};
23+
24+
/**
25+
* Stores resolved values for each participant and property path.
26+
*/
27+
export const participantPropertyState = selectorFamily<any, PropertyType>({
28+
key: RECOIL_PREFIX + 'participant-property',
29+
get:
30+
({ id, properties }) =>
31+
({ get }) => {
32+
const participant = get(participantState(id));
33+
return resolveParticipantPaths(participant, properties);
34+
},
35+
});
1036

1137
type UseParticipantPropertyReturnType<
1238
T extends ExtendedDailyParticipant,
@@ -29,16 +55,60 @@ export const useParticipantProperty = <
2955
participantId: string,
3056
propertyPaths: P
3157
): UseParticipantPropertyReturnType<T, P> => {
32-
const participantProperties = useRecoilValue(
33-
participantPropertyState({
34-
id: participantId,
35-
properties: (Array.isArray(propertyPaths)
36-
? propertyPaths
37-
: [propertyPaths]) as Paths<ExtendedDailyParticipant>[],
38-
})
58+
const [properties, setProperties] = useState<any[]>([]);
59+
60+
/**
61+
* Updates properties state, in case the passed list of values differs to what's currently in state.
62+
*/
63+
const maybeUpdateProperties = useCallback((properties: any[]) => {
64+
setProperties((prevProperties) => {
65+
if (deepEqual(properties, prevProperties)) return prevProperties;
66+
return properties;
67+
});
68+
}, []);
69+
70+
/**
71+
* Used to initialize the properties state, when the component mounts,
72+
* or the parameters change.
73+
*/
74+
const initProperties = useRecoilCallback(
75+
({ snapshot }) =>
76+
async () => {
77+
const properties = await snapshot.getPromise(
78+
participantPropertyState({
79+
id: participantId,
80+
properties: (Array.isArray(propertyPaths)
81+
? propertyPaths
82+
: [propertyPaths]) as Paths<ExtendedDailyParticipant>[],
83+
})
84+
);
85+
maybeUpdateProperties(properties);
86+
},
87+
[maybeUpdateProperties, participantId, propertyPaths]
3988
);
4089

41-
return Array.isArray(propertyPaths)
42-
? participantProperties
43-
: participantProperties[0];
90+
/**
91+
* Effect to initialize state when mounted.
92+
*/
93+
useEffect(() => {
94+
initProperties();
95+
}, [initProperties]);
96+
97+
/**
98+
* Asynchronously subscribes to updates to the participantPropertyState, without causing re-renders.
99+
* Anytime the recoil state returns a different list, we'll update this hook instance's state.
100+
*/
101+
useRecoilTransactionObserver_UNSTABLE(async ({ snapshot }) => {
102+
const properties = await snapshot.getPromise(
103+
participantPropertyState({
104+
id: participantId,
105+
properties: (Array.isArray(propertyPaths)
106+
? propertyPaths
107+
: [propertyPaths]) as Paths<ExtendedDailyParticipant>[],
108+
})
109+
);
110+
maybeUpdateProperties(properties);
111+
});
112+
113+
return Array.isArray(propertyPaths) ? properties : properties[0];
44114
};

0 commit comments

Comments
 (0)