From 0e3c272adc5b7f533f5e43b1d097b3517f95fcce Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 15 Sep 2022 23:47:20 +1000 Subject: [PATCH] fix user rerender race condition --- api/src/rpc.ts | 10 ++++++++- client/src/app.tsx | 56 +++++++++++++++++++++++++--------------------- client/src/ws.ts | 13 +++++++---- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/api/src/rpc.ts b/api/src/rpc.ts index 6838c68..6b1230e 100644 --- a/api/src/rpc.ts +++ b/api/src/rpc.ts @@ -66,6 +66,9 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off } async function onConnection() { + const userMsg: UserMessage = [RpcMessageType.User, user]; + send(userMsg); + const wants = await pg.userWants(user); const wantsMsg: WantsMessage = [RpcMessageType.Wants, wants]; send(wantsMsg); @@ -93,17 +96,20 @@ export enum RpcMessageType { Bundles = 'Bundles', Offers = 'Offers', List = 'List', + Wants = 'Wants', + User = 'User', + Error = 'Error', OfferStatusSet = 'OfferStatusSet', - Wants = 'Wants', WantRm = 'WantRm', } type ErrorMessage = [RpcMessageType.Error, string]; type PongMessage = [RpcMessageType.Pong, []]; type PingMessage = [RpcMessageType.Ping, []]; +type UserMessage = [RpcMessageType.User, User]; type WantsMessage = [RpcMessageType.Wants, Want[]]; type OffersMessage = [RpcMessageType.Offers, Offer[]]; type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]]; @@ -112,6 +118,8 @@ export type RpcMessage = PingMessage | PongMessage | + UserMessage | + WantsMessage | OffersMessage | diff --git a/client/src/app.tsx b/client/src/app.tsx index ef0ab8a..1882010 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -1,5 +1,6 @@ import { h } from 'preact'; import { useState, useEffect } from 'preact/hooks'; +import { useSelector, useDispatch } from 'react-redux' import { Route, Router, route } from 'preact-router'; import { Provider } from 'react-redux' @@ -15,38 +16,41 @@ import Login from './routes/login'; import Search from './routes/search'; import List from './routes/list'; -import store, { userState, wsState } from './store' +import store, { userState, wsState, State } from './store' -const ws = createWs(store); -ws.connect(); +const Main = () => { + const dispatch = useDispatch() -// dodgy, doesn't cause the header to rerender -async function init() { - const [error, user] = await http.getLogin(); - if (error) return route('/login'); - route('/bundles'); - store.dispatch(userState.actions.set(user)); - store.dispatch(wsState.actions.set(ws)); -} -init(); + // i have no idea why this is needed, + // but it makes sure the user changes actually rerender + useEffect(() => { + const ws = createWs(dispatch); + ws.connect(); + dispatch(wsState.actions.set(ws)); + }, [dispatch]) + + return ( +
+
+ + + + + + + + {/* ACP */} + + + +
+ ); +}; const App = () => { return ( -
-
- - - - - - - - {/* ACP */} - - - -
+
); } diff --git a/client/src/ws.ts b/client/src/ws.ts index c091289..769ebee 100644 --- a/client/src/ws.ts +++ b/client/src/ws.ts @@ -1,8 +1,8 @@ +import { wantsState, wsState, userState } from './store' + const SOCKET_URL = `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`; -import { wantsState, wsState } from './store' - -export default function createSocket(store) { +export default function createSocket(dispatch) { let ws; // ------------- @@ -42,8 +42,12 @@ export default function createSocket(store) { // ------------- // Incoming // ------------- + function onUser(user) { + dispatch(userState.actions.set(user)); + } + function onWants(wants) { - store.dispatch(wantsState.actions.set(wants)); + dispatch(wantsState.actions.set(wants)); } // ------------- @@ -53,6 +57,7 @@ export default function createSocket(store) { // this object wraps the reply types to a function const handlers = { Wants: onWants, + User: onUser, Pong: onPong, Error: errHandler,