Improve initial loading with useOnMount

This commit is contained in:
Corey 2024-05-21 11:30:06 -04:00
parent 11cb35d0ac
commit 20f5b9fa13
Signed by: coco
GPG Key ID: 051138DA6AEE3E60
4 changed files with 61 additions and 80 deletions

View File

@ -9,6 +9,7 @@ import {
Typography, Typography,
} from '@mui/material'; } from '@mui/material';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import { useOnMount } from '@mui/x-data-grid';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import { fetchDataFromBackend } from '../../apiUtil'; import { fetchDataFromBackend } from '../../apiUtil';
@ -38,7 +39,6 @@ export default function Header({
const { progress, setProgress, showAlert } = useLoadingContext(); const { progress, setProgress, showAlert } = useLoadingContext();
const [showSearchServer, setShowSearchServer] = useState(false); const [showSearchServer, setShowSearchServer] = useState(false);
const [filtersApplied, setFiltersApplied] = useState(false); const [filtersApplied, setFiltersApplied] = useState(false);
const [initialFetch, setInitialFetch] = useState(true);
const toggleShowSearchServer = () => { const toggleShowSearchServer = () => {
setShowSearchServer((prev) => !prev); setShowSearchServer((prev) => !prev);
}; };
@ -68,16 +68,15 @@ export default function Header({
}, 500); }, 500);
}, [showAlert, setServers, setProgress]); }, [showAlert, setServers, setProgress]);
useOnMount(() => {
fetchServerData();
});
useEffect(() => { useEffect(() => {
// TODO: Check if there's a better way to do this than "initialFetch" state, see also SearchServers
if (initialFetch) {
fetchServerData();
setInitialFetch(false);
}
setFiltersApplied( setFiltersApplied(
JSON.stringify(searchState) !== JSON.stringify(SearchStateDefaults) JSON.stringify(searchState) !== JSON.stringify(SearchStateDefaults)
); );
}, [initialFetch, fetchServerData, searchState]); }, [searchState]);
return ( return (
<Box> <Box>

View File

@ -12,6 +12,7 @@ import {
Tooltip, Tooltip,
Typography, Typography,
} from '@mui/material'; } from '@mui/material';
import { useOnMount } from '@mui/x-data-grid';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { SearchState, SearchStateDefaults } from '../../data/SearchState'; import { SearchState, SearchStateDefaults } from '../../data/SearchState';
@ -57,33 +58,25 @@ export default function SearchServers({
const location = useLocation(); const location = useLocation();
const [initialPath] = useState(location.pathname); const [initialPath] = useState(location.pathname);
const [contentHeight, setContentHeight] = useState(0); const [contentHeight, setContentHeight] = useState(0);
const [initialLoad, setInitialLoad] = useState(true);
useOnMount(() => {
if (initialPath === '/') {
const params = parseSearchParams(location.search);
if (JSON.stringify(params) !== JSON.stringify(SearchStateDefaults)) {
setSearchState(params);
}
}
});
useEffect(() => { useEffect(() => {
// Populate search state with URL params only if loading the home page // Populate search state with URL params only if loading the home page
// Home page manages updating URL params // Home page manages updating URL params
// TODO: Check if there's a better way to do this than "initialLoad" state, see also Header
if (initialLoad) {
if (initialPath === '/') {
const params = parseSearchParams(location.search);
if (JSON.stringify(params) !== JSON.stringify(SearchStateDefaults)) {
setSearchState(params);
}
}
setInitialLoad(false);
}
if (showSearchServer && containerRef.current) { if (showSearchServer && containerRef.current) {
setContentHeight(containerRef.current.scrollHeight); setContentHeight(containerRef.current.scrollHeight);
} else { } else {
setContentHeight(0); setContentHeight(0);
} }
}, [ }, [showSearchServer]);
showSearchServer,
location.search,
setSearchState,
initialPath,
initialLoad,
]);
const handleChange = ( const handleChange = (
name: string, name: string,

View File

@ -54,17 +54,17 @@ MAIN.ENABLE_TVR`;
variant="body1" variant="body1"
color={(theme) => alpha(theme.palette.text.primary, 0.87)} color={(theme) => alpha(theme.palette.text.primary, 0.87)}
> >
Ixion is a catalog of Final Fantasy XI private servers running the{' '} Ixion is a directory of public{' '}
<Link <Link
href="https://github.com/LandSandBoat/server" href="https://github.com/LandSandBoat/server"
target="_blank" target="_blank"
> >
LandSandBoat LandSandBoat
</Link>{' '} </Link>{' '}
software (or serving their API). Servers are updated every 10 (LSB) servers. Servers are updated every 10 minutes and are
minutes and are removed after a variable amount of unlisted after a variable amount of disconnectivity proportional
disconnectivity. All information is gathered directly from the to their time listed (maximum 24 hours). All information is
listed servers. gathered directly from the listed servers.
</Typography> </Typography>
</Box> </Box>
<Box className="mb-3"> <Box className="mb-3">
@ -158,7 +158,7 @@ MAIN.ENABLE_TVR`;
<CodeCard title="api.lua" content={apiLua} /> <CodeCard title="api.lua" content={apiLua} />
The world server needs to be restarted after any changes to any The world server needs to be restarted after any changes to any
of the settings. If you set <b>DO_NOT_TRACK</b> to <b>true</b>, of the settings. If you set <b>DO_NOT_TRACK</b> to <b>true</b>,
your server will be removed on the next update. your server will be unlisted on the next update.
</Typography> </Typography>
</Box> </Box>
<Box className="mb-3"> <Box className="mb-3">
@ -170,30 +170,12 @@ MAIN.ENABLE_TVR`;
variant="body1" variant="body1"
color={(theme) => alpha(theme.palette.text.primary, 0.87)} color={(theme) => alpha(theme.palette.text.primary, 0.87)}
> >
Anything that differs from the default LSB settings will be Any LSB settings that differ from the defaults will be displayed
displayed in the &quot;Settings Summary&quot; section for a in the &quot;Settings Summary&quot; section. The following
server. The following settings are always included as part of settings are always included as part of the UI:
the UI:
<CodeCard title="Settings" content={recommendedSettings} /> <CodeCard title="Settings" content={recommendedSettings} />
</Typography> </Typography>
</Box> </Box>
<Box className="mb-3">
<Typography align="center" variant="h6">
What if my server isn&apos;t running LSB?
</Typography>
<Typography
component="p"
variant="body1"
color={(theme) => alpha(theme.palette.text.primary, 0.87)}
>
If you&apos;re not running LSB, you could fake the API response.
You&apos;ll want to look at the LSB settings and serve whatever
relevant changes you&apos;ve made using the LSB equivalent, the
above listed settings at minimum. Settings should be served at{' '}
<b>/api/settings</b> and total active sessions should be served
at <b>/api/sessions</b>.
</Typography>
</Box>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
</Card> </Card>

View File

@ -1,5 +1,6 @@
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { useEffect, useState } from 'react'; import { useOnMount } from '@mui/x-data-grid';
import { useCallback, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { fetchDataFromBackend, fetchDemo } from '../apiUtil'; import { fetchDataFromBackend, fetchDemo } from '../apiUtil';
import ErrorCard from '../components/ErrorCard'; import ErrorCard from '../components/ErrorCard';
@ -9,41 +10,47 @@ import { useLoadingContext } from '../context/LoadingContext';
import { ServerData } from '../data/ServerData'; import { ServerData } from '../data/ServerData';
export default function ServerDetails() { export default function ServerDetails() {
const { showAlert } = useLoadingContext();
const { url } = useParams(); const { url } = useParams();
const [server, setServer] = useState<ServerData>(); const [server, setServer] = useState<ServerData | null>();
const [error, setError] = useState<string>(''); const { setProgress, showAlert } = useLoadingContext();
useEffect(() => { const fetchServerData = useCallback(async () => {
let data: ServerData; let data: ServerData | null = null;
const fetchServerData = async () => { try {
try { setProgress(25);
if (url === 'demo') { if (url === 'demo') {
data = await fetchDemo(); data = await fetchDemo();
} else { } else {
data = await fetchDataFromBackend(`server/?url=${url}`); data = await fetchDataFromBackend(`server/?url=${url}`);
}
} catch (err) {
if (err instanceof Error) {
showAlert({
message: err.message,
severity: 'error',
});
} else {
setError('An unknown error occurred.');
}
} }
} catch (err) {
if (err instanceof Error) {
showAlert({
message: err.message,
severity: 'error',
});
} else {
showAlert({
message: 'An unknown error occurred.',
severity: 'error',
});
}
}
setServer(data);
setProgress(100);
setTimeout(() => {
setProgress(0);
}, 500);
}, [url, showAlert, setServer, setProgress]);
setServer(data); useOnMount(() => {
};
fetchServerData(); fetchServerData();
}, [url, setServer, showAlert, setError]); });
return ( return (
<Box> <Box>
{error || !server ? ( {!server ? (
<ErrorCard error={error} /> <ErrorCard error="" />
) : ( ) : (
<ServerCard server={server}> <ServerCard server={server}>
{server.settings && ( {server.settings && (