Skip to content

Commit 47282f6

Browse files
authored
Merge pull request #460 from BloomBooks/optimizeBRLangs
Various optimizations, mainly for BloomReader
2 parents da04e6d + 6ec5148 commit 47282f6

11 files changed

Lines changed: 131 additions & 117 deletions

public/index.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@
4848
</head>
4949
<body>
5050
<noscript>You need to enable JavaScript to run this app.</noscript>
51-
<div id="root"></div>
51+
<div id="root">Loading...</div>
5252
<!--
5353
This HTML file is a template.
54-
If you open it directly in the browser, you will see an empty page.
54+
If you open it directly in the browser, you will just see the Loading message.
55+
(It's there so something can be seen while fetching the code.)
5556
5657
You can add webfonts, meta tags, or analytics to this file.
5758
The build step will place the bundled scripts into the <body> tag.

src/components/BookCardGroup.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from "../connection/LibraryQueryHooks";
1818
import { BookCard, useBookCardSpec } from "./BookCard";
1919
import { MoreCard } from "./MoreCard";
20-
import { CardSwiperLazy } from "./CardSwiper";
20+
import { CardSwiperCodeSplit } from "./CardSwiperCodeSplit";
2121
import { ICollection } from "../model/ContentInterfaces";
2222
import Typography from "@material-ui/core/Typography";
2323
import { getLocalizedCollectionLabel } from "../localization/CollectionLabel";
@@ -157,7 +157,7 @@ const BookCardGroupInner: React.FunctionComponent<IProps> = (props) => {
157157
data.push("more");
158158
}
159159
bookList = (
160-
<CardSwiperLazy
160+
<CardSwiperCodeSplit
161161
data={data}
162162
cardSpec={cardSpec}
163163
getReactElement={(item: IBasicBookInfo | "more", index) => {
@@ -180,7 +180,7 @@ const BookCardGroupInner: React.FunctionComponent<IProps> = (props) => {
180180
);
181181
}
182182
}}
183-
></CardSwiperLazy>
183+
></CardSwiperCodeSplit>
184184
);
185185
} else {
186186
const verticalSpacing = cardSpec.cardSpacingPx;

src/components/BookGroup.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ import {
1515
IBasicBookInfo,
1616
} from "../connection/LibraryQueryHooks";
1717
import { BookCard, useBookCardSpec } from "./BookCard";
18-
import { SingleRowCardSwiper } from "./SingleRowCardSwiper";
1918
import { useResponsiveChoice } from "../responsiveUtilities";
2019
import { BookOrderingScheme } from "../model/ContentInterfaces";
20+
import { CardSwiperCodeSplit } from "./CardSwiperCodeSplit";
2121

2222
interface IProps {
2323
title: string;
2424
order?: string;
2525
// I don't know... this could be "bookLimit" instead "rows". Have to think in terms
2626
// of mobile versus big screen.... hmmm...
27+
// Warning: if rows is 1 or unspecified, BookGroup shows a swiper row; this does not seem to be
28+
// working well at least in our stories, but it is not used in the real website as of Sep 2022.
2729
rows?: number;
2830

2931
contextLangIso?: string;
@@ -172,10 +174,24 @@ export const BookGroupInner: React.FunctionComponent<IProps> = (props) => {
172174
// );
173175
// }
174176

175-
// JH Jan 2020: I cannot find anywhere that this is showInOne Row is used.
176-
// It's also puzzling that it has to have its own CardSwiper implementation.
177+
// JT Sep 2022: showInOneRow is true only when BookGroup is either told to show exactly one row, or
178+
// not told how many rows to show. Currently this happens only in the various stories which were written
179+
// early on to test it; the only real use of BookGroup is in ByLanguageGroups, which passes 999.
180+
// When I tried the stories in Sep 2022, they were working very badly: showing a set of cards
181+
// with no spacing. I wanted to retire the obsolete SingleRowCardSwiper, so I switched this rather crudely
182+
// to use our current CardSwiperLazy. This looks a bit better but the book cards are not getting their
183+
// images. Since this currently only shows up in test stories that we don't seem to be using, I decided
184+
// not to try to fix it.
185+
const cardSpec = useBookCardSpec();
177186
const bookList = showInOneRow ? (
178-
<SingleRowCardSwiper wrapperRole="list">{cards}</SingleRowCardSwiper>
187+
<CardSwiperCodeSplit
188+
data={cards}
189+
getReactElement={(x) => x}
190+
wrapperRole="list"
191+
cardSpec={cardSpec}
192+
>
193+
{cards}
194+
</CardSwiperCodeSplit>
179195
) : (
180196
<div
181197
css={css`

src/components/ByLanguageGroups.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ export const ByLanguageGroups: React.FunctionComponent<{
4141
titlePrefix: string;
4242
collection: ICollection;
4343
reportBooksAndLanguages?: (bookCount: number, langCount: number) => void;
44-
rowsPerLanguage?: number;
4544
// Sometimes it's nice to drop English, in particular.
4645
excludeLanguages?: string[];
4746
}> = (props) => {
@@ -195,7 +194,7 @@ export const ByLanguageGroups: React.FunctionComponent<{
195194
}`}
196195
predeterminedBooks={books}
197196
contextLangIso={l.isoCode}
198-
rows={props.rowsPerLanguage ?? 999}
197+
rows={999}
199198
/>
200199
);
201200
})}

src/components/CardRow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { jsx } from "@emotion/core";
55
/** @jsx jsx */
66
import React, { ReactElement } from "react";
77
import LazyLoad from "react-lazyload";
8-
import { CardSwiperLazy } from "./CardSwiper";
8+
import { CardSwiperCodeSplit } from "./CardSwiperCodeSplit";
99
import { ICollection } from "../model/ContentInterfaces";
1010
import {
1111
CollectionLabel,
@@ -39,7 +39,7 @@ export const CardRow: React.FunctionComponent<IProps> = (props) => {
3939
padding-left: 0;
4040
`}
4141
>
42-
<CardSwiperLazy
42+
<CardSwiperCodeSplit
4343
wrapperRole="list"
4444
data={props.data}
4545
getReactElement={props.getCards}

src/components/CardSwiper.tsx

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import "swiper/components/a11y/a11y.min.css";
1313
import { useResponsiveChoice } from "../responsiveUtilities";
1414
import { ICardSpec } from "./CardGroup";
1515
import { commonUI } from "../theme";
16+
import { ICardSwiperProps } from "./CardSwiperCodeSplit";
1617

1718
SwiperCore.use([Navigation, A11y]);
1819

19-
export const swiperConfig: Swiper = {
20+
const swiperConfig: Swiper = {
2021
preloadImages: false,
2122
lazy: {
2223
loadPrevNext: true,
@@ -48,22 +49,7 @@ export const swiperConfig: Swiper = {
4849
// small windows.
4950
// Enhance: this could be made generic, with a type param indicating that the type of objects in data
5051
// is the same as the type passed as the first argument of getReactElement
51-
export const CardSwiperLazy: React.FunctionComponent<{
52-
data: any[];
53-
// Given one of the items in data (and its index), return the react element that should be
54-
// shown for that card when it is visible.
55-
getReactElement: (card: any, index: number) => ReactElement;
56-
57-
// Typically the swiper is a list. I can't find a way to configure it so that the element containing
58-
// the cards is a UL, but by setting this to 'list' and making items with role listitem we achieve
59-
// the same accessibility goals. This role becomes the value of the role attribute of the swiper
60-
// wrapper element, which is the immediate parent of the items. Note that it's not always a list, e.g.,
61-
// in the LanguageGroup a further-out element is a listbox and the items have role 'option'.
62-
// If you set a wrapperRole, make sure the children you pass have role listitem.
63-
wrapperRole?: string;
64-
65-
cardSpec: ICardSpec;
66-
}> = (props) => {
52+
const CardSwiperLazy: React.FunctionComponent<ICardSwiperProps> = (props) => {
6753
const [swiper, setSwiper] = useState<any | null>(null);
6854
const getResponsiveChoice = useResponsiveChoice();
6955
const [showAll, setShowAll] = useState(false);
@@ -212,3 +198,5 @@ export const CardSwiperLazy: React.FunctionComponent<{
212198
</Swiper>
213199
);
214200
};
201+
202+
export default CardSwiperLazy;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React, { ReactElement } from "react";
2+
import { ICardSpec } from "./CardGroup";
3+
4+
export interface ICardSwiperProps {
5+
data: any[];
6+
// Given one of the items in data (and its index), return the react element that should be
7+
// shown for that card when it is visible.
8+
getReactElement: (card: any, index: number) => ReactElement;
9+
10+
// Typically the swiper is a list. I can't find a way to configure it so that the element containing
11+
// the cards is a UL, but by setting this to 'list' and making items with role listitem we achieve
12+
// the same accessibility goals. This role becomes the value of the role attribute of the swiper
13+
// wrapper element, which is the immediate parent of the items. Note that it's not always a list, e.g.,
14+
// in the LanguageGroup a further-out element is a listbox and the items have role 'option'.
15+
// If you set a wrapperRole, make sure the children you pass have role listitem.
16+
wrapperRole?: string;
17+
18+
cardSpec: ICardSpec;
19+
}
20+
21+
// This is wrapped so that we can keep all the javascript involved in the CardSwiper
22+
// in a separate js file, downloaded to the user's browser only if he/she needs it.
23+
export const CardSwiperCodeSplit: React.FunctionComponent<ICardSwiperProps> = (
24+
props
25+
) => {
26+
const CardSwiperLazy = React.lazy(
27+
() => import(/* webpackChunkName: "cardSwiper" */ "./CardSwiper")
28+
);
29+
return (
30+
<React.Suspense fallback={<div>Loading Cards...</div>}>
31+
<CardSwiperLazy {...props} />
32+
</React.Suspense>
33+
);
34+
};

src/components/LanguageGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import matchSorter from "match-sorter";
1818
import searchIcon from "../search.png";
1919
import { CachedTablesContext } from "../model/CacheProvider";
2020
import { ILanguage } from "../model/Language";
21-
import { CardSwiperLazy } from "./CardSwiper";
21+
import { CardSwiperCodeSplit } from "./CardSwiperCodeSplit";
2222
import { Redirect } from "react-router-dom";
2323
import { FormattedMessage, useIntl } from "react-intl";
2424
import { propsToHideAccessibilityElement } from "../Utilities";
@@ -54,7 +54,7 @@ export const LanguageGroup: React.FunctionComponent = () => {
5454
if (languagesToDisplay.length) {
5555
return (
5656
<div {...getMenuProps({})}>
57-
<CardSwiperLazy
57+
<CardSwiperCodeSplit
5858
data={languagesToDisplay}
5959
cardSpec={cardSpec}
6060
getReactElement={(l: ILanguage, index: number) => (

src/components/SingleRowCardSwiper.tsx

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/connection/LibraryQueryHooks.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,19 @@ export interface IParseResponseDataWithCount<T = any> {
5757
/**
5858
* @summary For things other than books, which should use `useBookQuery()`
5959
* @param T The type of the result record returned by Parse. Or use "any" or omit to ignore types.
60+
* If doNotActuallyRunQuery is true, the query will not be executed, and the result will always be empty.
61+
* (This is useful when rules of hooks force us to call this unconditionally, but we sometimes don't want to.)
6062
*/
6163
function useLibraryQuery<T = any>(
6264
queryClass: string,
63-
params: {}
65+
params: {},
66+
doNotActuallyRunQuery?: boolean
6467
): IReturns<IParseResponseData<T>> {
6568
return useAxios<IParseResponseData<T>>({
6669
url: `${getConnection().url}classes/${queryClass}`,
6770
method: "GET",
6871
trigger: "true",
72+
forceDispatchEffect: () => !doNotActuallyRunQuery,
6973
options: {
7074
headers: getConnection().headers,
7175
params,
@@ -78,11 +82,14 @@ function useLibraryQuery<T = any>(
7882
*/
7983
function useLibraryQueryWithCount<T = any>(
8084
queryClass: string,
81-
params: {}
85+
params: {},
86+
doNotActuallyRunQuery?: boolean
8287
): IReturns<IParseResponseDataWithCount<T>> {
83-
return useLibraryQuery(queryClass, { ...params, count: 1 }) as IReturns<
84-
IParseResponseDataWithCount<T>
85-
>;
88+
return useLibraryQuery(
89+
queryClass,
90+
{ ...params, count: 1 },
91+
doNotActuallyRunQuery
92+
) as IReturns<IParseResponseDataWithCount<T>>;
8693
}
8794

8895
function useGetLanguagesList() {
@@ -103,10 +110,20 @@ export function useGetCleanedAndOrderedLanguageList(): ILanguage[] {
103110
return [];
104111
}
105112
export function useGetTagList(): string[] {
106-
const axiosResult = useLibraryQueryWithCount("tag", {
107-
limit: Number.MAX_SAFE_INTEGER,
108-
order: "name",
109-
});
113+
// I'd prefer to use useAppHosted but it crashes, I think because this code runs outside the
114+
// scope where it works.
115+
const appHosted = isAppHosted();
116+
const axiosResult = useLibraryQueryWithCount(
117+
"tag",
118+
{
119+
limit: Number.MAX_SAFE_INTEGER,
120+
order: "name",
121+
},
122+
appHosted // don't actually run the query if we're app hosted; we don't need tags
123+
);
124+
if (appHosted) {
125+
return ["dummy"]; // don't need the list, but need non-empty to stop waiting.
126+
}
110127

111128
if (axiosResult.response?.data?.results) {
112129
assertAllParseRecordsReturned(axiosResult.response);

0 commit comments

Comments
 (0)