useXxxReducer

This commit is contained in:
djmil 2023-11-08 09:23:20 +01:00
parent 9ec2059c4a
commit b58c71c876
9 changed files with 84 additions and 56 deletions

View File

@ -1,31 +1,34 @@
import './App.css';
import React, { useReducer } from 'react'
import { BrowserRouter, Routes, Route } from "react-router-dom"
import React from 'react';
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Header from "./container/Header"
import Leaderboard from "./container/Leaderboard"
import Game from "./components/Game"
import About from "./components/About"
import Polling from './flux/polling';
import User from './flux/user';
import usePollingReducer from './reducer/polling';
import useUserReducer from './reducer/user';
import useLeaderboardReducer from './reducer/leaderboard';
import useLeaderboardApi from './api/leaderboard';
import useUserApi from './api/user';
function App() {
const pollingFlux = useReducer(Polling.reducer, Polling.initialState);
const userFlux = useReducer(User.reducer, User.initialState);
const pollingReducer = usePollingReducer();
const userReducer = useUserReducer();
const leaderboardReducer = useLeaderboardReducer();
const leaderboardApi = useLeaderboardApi(pollingFlux);
const userApi = useUserApi(userFlux);
const leaderboardApi = useLeaderboardApi(leaderboardReducer);
const userApi = useUserApi(userReducer);
const leaderboard = leaderboardApi.get();
const leaderboard = leaderboardApi.get(pollingReducer);
const user = userApi.get();
return (
<div className="App" >
<BrowserRouter>
<Header pollingFlux={pollingFlux} />
<Header pollingReducer={pollingReducer} />
<Routes>
{/* https://stackoverflow.com/questions/40541994/multiple-path-names-for-a-same-component-in-react-router */}
<Route path="/game" element={<Game />} />

View File

@ -2,19 +2,26 @@ import usePolling from "../util/Polling"
const uri = '/api/leaderboard';
export default function useLeaderboardApi([polling, dispatchPolling]) {
export default function useLeaderboardApi(leaderboardReducer) {
const [leaderboard, dispatchLeaderboaed] = leaderboardReducer;
const useGet = (pollingReducer) => {
const [polling, dispatchPolling] = pollingReducer;
const useGet = () => {
const mode = (polling.enabled === true)
? { interval_sec: 300 } // update leaderbord stats every 5 min
: { interval_stop: true } // user has fliped OfflineToggel
const [leaderboard, isFetching] = usePolling(uri, mode);
const [table, isFetching] = usePolling(uri, mode);
if (polling.leaderboard !== isFetching) {
dispatchPolling({ type: 'next', leaderboard: isFetching });
}
if (leaderboard.table !== table) {
dispatchLeaderboaed({ type: 'next', table });
}
return leaderboard;
}

View File

@ -4,8 +4,8 @@ import { NavLink } from "react-router-dom";
import OnlineToggle from '../components/OnlineToggle';
import Wobler from '../components/Wobler';
export default function Header({ pollingFlux }) {
const [polling, dispatchPolling] = pollingFlux;
export default function Header({ pollingReducer }) {
const [polling, dispatchPolling] = pollingReducer;
return (
<div className='Header'>

View File

@ -4,14 +4,15 @@ import Loading from '../components/Loading';
export default function Leaderboard({ leaderboard, user }) {
if (leaderboard == null)
const table = leaderboard?.table;
if (!table)
return <Loading />
const isCurrentUser = (playerName) =>
user.isCurrentUser(playerName) === true ? true : null;
user?.isCurrentUser(playerName) === true ? true : null;
const tableRows = Object.keys(leaderboard).map(playerName => {
var rank = leaderboard[playerName];
const tableRows = Object.keys(table).map(playerName => {
var rank = table[playerName];
return <tr key={playerName} className={isCurrentUser(playerName) && 'currentuser'}>
<td>{playerName}</td>

View File

@ -1,28 +0,0 @@
import { localeCompare } from '../util/Locale'
import StateHelper from '../util/StateHelper';
export const userInitialState = {
username: '',
isCurrentUser: function (otherUsername) {
return localeCompare(this.username, otherUsername)
},
};
export function userReducer(state, action) {
switch (action.type) {
case 'next':
return StateHelper.next(state, action);
default:
throw Error('Unknown action.type: ' + action.type);
}
}
const User = {
reducer: userReducer,
initialState: userInitialState
};
export default User;

View File

@ -0,0 +1,21 @@
import { useReducer } from 'react';
import { nextState } from '../util/StateHelper';
export const leaderboardInitialState = {
table: null,
};
export function leaderboardReducer(state, action) {
switch (action.type) {
case 'next':
return nextState(state, action);
default:
throw Error('LeaderboardReducer: Unknown action.type', action.type);
}
}
export default function useLeaderboardReducer() {
return useReducer(leaderboardReducer, leaderboardInitialState);
}

View File

@ -1,4 +1,5 @@
import { useLocalStorage } from '../util/PersistentStorage'
import { useReducer } from 'react';
import { useLocalStorage } from '../util/PersistentStorage';
import { nextState } from '../util/StateHelper';
const Persistent = (() => {
@ -33,9 +34,6 @@ export function pollingReducer(curntState, action) {
}
}
const Polling = {
reducer: pollingReducer,
initialState: pollingInitialState
};
export default Polling
export default function usePollingReducer() {
return useReducer(pollingReducer, pollingInitialState);
}

View File

@ -0,0 +1,26 @@
import { useReducer } from 'react';
import { localeCompare } from '../util/Locale';
import { nextState } from '../util/StateHelper';
export const userInitialState = {
username: '',
isCurrentUser: function (otherUsername) {
return localeCompare(this.username, otherUsername)
}
};
export function userReducer(state, action) {
switch (action.type) {
case 'next':
return nextState(state, action);
default:
throw Error('Unknown action.type', action.type);
}
}
export default function useUserReducer() {
return useReducer(userReducer, userInitialState);
}

View File

@ -47,7 +47,7 @@ export default function usePolling(url, mode) {
}, [url, mode, isFetching, cache, fetchData, delayID]);
return [
cache, // API response
cache, // API responce
isFetching // true / false
]
}