Changed useNetworkState to implement a partial update mechanism

This commit is contained in:
Mitchell McCaffrey 2021-01-03 10:45:24 +11:00
parent 858c489980
commit 02ecf9bffc
3 changed files with 39 additions and 15 deletions

View File

@ -22,7 +22,9 @@ export function PlayerProvider({ session, children }) {
userId,
},
session,
"player_state"
"player_state",
100,
false
);
useEffect(() => {

9
src/helpers/diff.js Normal file
View File

@ -0,0 +1,9 @@
import { applyChange, diff as deepDiff } from "deep-diff";
export function applyChanges(target, changes) {
for (let change of changes) {
applyChange(target, true, change);
}
}
export const diff = deepDiff;

View File

@ -1,13 +1,14 @@
import { useEffect, useState, useRef, useCallback } from "react";
import { applyChange, diff } from "deep-diff";
import useDebounce from "./useDebounce";
import { diff, applyChanges } from "./diff";
function useNetworkedState(
defaultState,
session,
eventName,
debounceRate = 100
debounceRate = 100,
partialUpdates = true
) {
const [state, _setState] = useState(defaultState);
// Used to control whether the state needs to be sent to the socket
@ -25,31 +26,43 @@ function useNetworkedState(
}, [eventName]);
const debouncedState = useDebounce(state, debounceRate);
const lastSyncedStateRef = useRef();
useEffect(() => {
if (session.socket && dirtyRef.current) {
session.socket.emit(eventName, debouncedState);
// If partial updates enabled, send just the changes to the socket
if (lastSyncedStateRef.current && debouncedState && partialUpdates) {
const changes = diff(lastSyncedStateRef.current, debouncedState);
if (changes) {
session.socket.emit(`${eventName}_update`, changes);
}
} else {
session.socket.emit(eventName, debouncedState);
}
dirtyRef.current = false;
lastSyncedStateRef.current = debouncedState;
}
}, [session.socket, eventName, debouncedState]);
// Store the uncommitted changes so we can re-apply them when receiving new data
const uncommittedChangesRef = useRef();
useEffect(() => {
uncommittedChangesRef.current = diff(debouncedState, state);
}, [state, debouncedState]);
}, [session.socket, eventName, debouncedState, partialUpdates]);
useEffect(() => {
function handleSocketEvent(data) {
const uncommittedChanges = uncommittedChangesRef.current || [];
for (let change of uncommittedChanges) {
applyChange(data, true, change);
}
_setState(data);
lastSyncedStateRef.current = data;
}
function handleSocketUpdateEvent(changes) {
_setState((prevState) => {
let newState = { ...prevState };
applyChanges(newState, changes);
lastSyncedStateRef.current = newState;
return newState;
});
}
session.socket?.on(eventName, handleSocketEvent);
session.socket?.on(`${eventName}_update`, handleSocketUpdateEvent);
return () => {
session.socket?.off(eventName, handleSocketEvent);
session.socket?.off(`${eventName}_update`, handleSocketUpdateEvent);
};
}, [session.socket, eventName]);