Skip to content

Commit

Permalink
[graphiql-react] create instance of new HistoryStore and `new Stora…
Browse files Browse the repository at this point in the history
…geAPI` only on mount, use function with `useState` (#3743)

* create instance of `new HistoryStore` and `new StorageAPI` only on mount, use function with `useState`

* aa
  • Loading branch information
dimaMachina authored Aug 22, 2024
1 parent 26cd829 commit 7275c19
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/pretty-panthers-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphiql/react': patch
---

create instance of `new HistoryStore` and `new StorageAPI` only on mount, use function with `useState`
89 changes: 28 additions & 61 deletions packages/graphiql-react/src/history/context.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HistoryStore, QueryStoreItem, StorageAPI } from '@graphiql/toolkit';
import { ReactNode, useCallback, useMemo, useRef, useState } from 'react';
import { ReactNode, useMemo, useState } from 'react';

import { useStorageContext } from '../storage';
import { createContextHook, createNullableContext } from '../utility/context';
Expand Down Expand Up @@ -87,77 +87,44 @@ export type HistoryContextProviderProps = {
* any additional props they added for their needs (i.e., build their own functions that may save
* to a backend instead of localStorage and might need an id property added to the QueryStoreItem)
*/
export function HistoryContextProvider(props: HistoryContextProviderProps) {
export function HistoryContextProvider({
maxHistoryLength = DEFAULT_HISTORY_LENGTH,
children,
}: HistoryContextProviderProps) {
const storage = useStorageContext();
const historyStore = useRef(
new HistoryStore(
const [historyStore] = useState(
() =>
// Fall back to a noop storage when the StorageContext is empty
storage || new StorageAPI(null),
props.maxHistoryLength || DEFAULT_HISTORY_LENGTH,
),
new HistoryStore(storage || new StorageAPI(null), maxHistoryLength),
);
const [items, setItems] = useState(historyStore.current?.queries || []);

const addToHistory: HistoryContextType['addToHistory'] = useCallback(
(operation: QueryStoreItem) => {
historyStore.current?.updateHistory(operation);
setItems(historyStore.current.queries);
},
[],
);

const editLabel: HistoryContextType['editLabel'] = useCallback(
(operation: QueryStoreItem, index?: number) => {
historyStore.current.editLabel(operation, index);
setItems(historyStore.current.queries);
},
[],
);

const toggleFavorite: HistoryContextType['toggleFavorite'] = useCallback(
(operation: QueryStoreItem) => {
historyStore.current.toggleFavorite(operation);
setItems(historyStore.current.queries);
},
[],
);

const setActive: HistoryContextType['setActive'] = useCallback(
(item: QueryStoreItem) => {
return item;
},
[],
);

const deleteFromHistory: HistoryContextType['deleteFromHistory'] =
useCallback((item: QueryStoreItem, clearFavorites = false) => {
historyStore.current.deleteHistory(item, clearFavorites);
setItems(historyStore.current.queries);
}, []);
const [items, setItems] = useState(() => historyStore.queries || []);

const value = useMemo<HistoryContextType>(
() => ({
addToHistory,
editLabel,
addToHistory(operation) {
historyStore.updateHistory(operation);
setItems(historyStore.queries);
},
editLabel(operation, index) {
historyStore.editLabel(operation, index);
setItems(historyStore.queries);
},
items,
toggleFavorite,
setActive,
deleteFromHistory,
toggleFavorite(operation) {
historyStore.toggleFavorite(operation);
setItems(historyStore.queries);
},
setActive: item => item,
deleteFromHistory(item, clearFavorites) {
historyStore.deleteHistory(item, clearFavorites);
setItems(historyStore.queries);
},
}),
[
addToHistory,
editLabel,
items,
toggleFavorite,
setActive,
deleteFromHistory,
],
[items, historyStore],
);

return (
<HistoryContext.Provider value={value}>
{props.children}
</HistoryContext.Provider>
<HistoryContext.Provider value={value}>{children}</HistoryContext.Provider>
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/graphiql-react/src/storage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type StorageContextProviderProps = {
children: ReactNode;
/**
* Provide a custom storage API.
* @default `localStorage``
* @default `localStorage`
* @see {@link https://graphiql-test.netlify.app/typedoc/modules/graphiql_toolkit.html#storage-2|API docs}
* for details on the required interface.
*/
Expand All @@ -21,7 +21,7 @@ export type StorageContextProviderProps = {

export function StorageContextProvider(props: StorageContextProviderProps) {
const isInitialRender = useRef(true);
const [storage, setStorage] = useState(new StorageAPI(props.storage));
const [storage, setStorage] = useState(() => new StorageAPI(props.storage));

useEffect(() => {
if (isInitialRender.current) {
Expand Down

0 comments on commit 7275c19

Please sign in to comment.