Improve scroll handling and cache fetch results

This commit is contained in:
Tanner Collin 2020-02-17 00:19:44 +00:00
parent 2aff4e97b6
commit 8555fbfa0f
6 changed files with 76 additions and 19 deletions

View File

@ -38,19 +38,17 @@ export function Admin(props) {
</a> </a>
</p> </p>
<p> Automate with wget (keep secret, that's <b>your</b> login token): <br />
Automate with wget (keep secret, that's <b>your</b> login token): {reveal ?
{reveal ? <pre>
<pre> wget \
wget \ <br /> --content-disposition \
<br /> --content-disposition \ <br /> --header="Authorization: Token {token}" \
<br /> --header="Authorization: Token {token}" \ <br /> {apiUrl}/backup/
<br /> {apiUrl}/backup/ </pre>
</pre> :
: <Button onClick={() => setReveal(true)}>Show Secret</Button>
<div><Button onClick={() => setReveal(true)}>Show Secret</Button></div> }
}
</p>
</div> </div>
: :
<p>Loading...</p> <p>Loading...</p>

View File

@ -4,6 +4,7 @@ import './semantic-ui/semantic.min.css';
import './light.css'; import './light.css';
import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
import { isAdmin, requester } from './utils.js'; import { isAdmin, requester } from './utils.js';
import { ManageScroll } from './ManageScroll.js';
import { Home } from './Home.js'; import { Home } from './Home.js';
import { Account } from './Account.js'; import { Account } from './Account.js';
import { Transactions, TransactionDetail } from './Transactions.js'; import { Transactions, TransactionDetail } from './Transactions.js';
@ -71,6 +72,8 @@ function App() {
return ( return (
<div> <div>
<ManageScroll />
<div className='content-wrap'> <div className='content-wrap'>
<div className='content-wrap-inside'> <div className='content-wrap-inside'>

View File

@ -48,14 +48,17 @@ function ClassTable(props) {
); );
}; };
let classesCache = false;
export function Classes(props) { export function Classes(props) {
const [classes, setClasses] = useState(false); const [classes, setClasses] = useState(classesCache);
const { token } = props; const { token } = props;
useEffect(() => { useEffect(() => {
requester('/sessions/', 'GET', token) requester('/sessions/', 'GET', token)
.then(res => { .then(res => {
setClasses(res.results); setClasses(res.results);
classesCache = res.results;
}) })
.catch(err => { .catch(err => {
console.log(err); console.log(err);

View File

@ -8,14 +8,17 @@ import { NotFound, PleaseLogin } from './Misc.js';
import { InstructorCourseList, InstructorCourseDetail } from './InstructorCourses.js'; import { InstructorCourseList, InstructorCourseDetail } from './InstructorCourses.js';
import { InstructorClassList } from './InstructorClasses.js'; import { InstructorClassList } from './InstructorClasses.js';
let courseCache = false;
export function Courses(props) { export function Courses(props) {
const [courses, setCourses] = useState(false); const [courses, setCourses] = useState(courseCache);
const { token, user } = props; const { token, user } = props;
useEffect(() => { useEffect(() => {
requester('/courses/', 'GET', token) requester('/courses/', 'GET', token)
.then(res => { .then(res => {
setCourses(res.results); setCourses(res.results);
courseCache = res.results;
}) })
.catch(err => { .catch(err => {
console.log(err); console.log(err);

View File

@ -0,0 +1,44 @@
import React, { useState, useEffect, useReducer, useContext } from 'react';
import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom';
let scrollPositions = {};
let timeout = null;
export function ManageScroll() {
const history = useHistory();
const scrollListener = () => {
if (timeout) {
window.cancelAnimationFrame(timeout);
}
timeout = window.requestAnimationFrame(() => {
const key = history.location.key;
if (key in scrollPositions) {
scrollPositions[key] = window.scrollY;
}
});
};
useEffect(() => {
window.addEventListener('scroll', scrollListener);
return () => {
window.removeEventListener('scroll', scrollListener);
}
}, []);
useEffect(() => {
const key = history.location.key;
if (key in scrollPositions) {
window.scrollTo(0, scrollPositions[key]);
} else {
window.scrollTo(0, 0);
scrollPositions[key] = 0;
}
}, [history.location]);
return (
null
);
};

View File

@ -49,13 +49,16 @@ export function MembersDropdown(props) {
); );
}; };
let searchCache = '';
export function Members(props) { export function Members(props) {
const [response, setResponse] = useState(false); const [response, setResponse] = useState(false);
const searchDefault = {seq: 0, q: ''}; const searchDefault = {seq: 0, q: searchCache};
const [search, setSearch] = useState(searchDefault); const [search, setSearch] = useState(searchDefault);
const { token } = props; const { token } = props;
useEffect(() => { useEffect(() => {
searchCache = search.q;
requester('/search/', 'POST', token, search) requester('/search/', 'POST', token, search)
.then(res => { .then(res => {
if (!search.seq || res.seq > response.seq) { if (!search.seq || res.seq > response.seq) {
@ -82,7 +85,7 @@ export function Members(props) {
{search.q.length ? {search.q.length ?
<Button <Button
content='Clear' content='Clear'
onClick={() => setSearch(searchDefault)} onClick={() => setSearch({seq: 0, q: ''})}
/> : '' /> : ''
} }
@ -118,17 +121,20 @@ export function Members(props) {
); );
}; };
let resultCache = {};
export function MemberDetail(props) { export function MemberDetail(props) {
const [result, setResult] = useState(false); const { id } = useParams();
const [result, setResult] = useState(resultCache[id] || false);
const [refreshCount, refreshResult] = useReducer(x => x + 1, 0); const [refreshCount, refreshResult] = useReducer(x => x + 1, 0);
const [error, setError] = useState(false); const [error, setError] = useState(false);
const { token, user } = props; const { token, user } = props;
const { id } = useParams();
useEffect(() => { useEffect(() => {
requester('/search/'+id+'/', 'GET', token) requester('/search/'+id+'/', 'GET', token)
.then(res => { .then(res => {
setResult(res); setResult(res);
resultCache[id] = res;
}) })
.catch(err => { .catch(err => {
console.log(err); console.log(err);