Gate article detail on a store-backed cache so the view paints once.

Sku page loads/caches the article before mounting ArticleView; the view reads sync from StorageManager instead of fetching again.
This commit is contained in:
seb
2026-08-05 17:31:12 +02:00
parent 198e800fd3
commit 4352a02d4e
3 changed files with 137 additions and 166 deletions

View File

@@ -7,6 +7,10 @@ import {
buildCategoryPath,
defaultCategoryPath,
} from '../../pages/artikel/categoryRoute';
import {
artikelDetailPath,
resolveArticleTab,
} from '../../pages/artikel/articleRoute';
import ArticleTileTab from './ArticleTileTab';
import ArticlePhotoTile from './ArticlePhotoTile';
@@ -17,28 +21,55 @@ import ArticleViewEANs from './boxes/ArticleViewEANs';
import ArticleViewPrice from './boxes/ArticleViewPrice';
import ArticleViewLists from './boxes/ArticleViewLists';
function viewStateFromStore(store, sku) {
const categoryState = store.getCategoryState();
return {
article: store.getArticle(sku) ?? null,
categories: categoryState?.categories ?? null,
rootCategoryId: categoryState?.rootCategoryId ?? null,
};
}
class ArticleView extends Component {
static contextType = StorageManagerContext;
constructor(props, context) {
super(props, context);
this.state = viewStateFromStore(context, props.sku);
}
componentDidUpdate(prevProps) {
const { sku, tab, navigate } = this.props;
const { article } = this.state;
if (prevProps.sku !== sku) {
this.setState(viewStateFromStore(this.context, sku));
return;
}
if (!article) return;
const resolved = resolveArticleTab(tab, article);
if (tab !== resolved) {
navigate(artikelDetailPath(article, resolved), { replace: true });
}
}
refreshSearchCaches = () => {
void this.context.updateArticleIndex();
void this.context.updateCategoryTree();
};
handleArticleUpdated = (next) => {
this.props.onArticleUpdated?.(next);
this.context.setArticle(next);
this.setState({ article: next });
this.refreshSearchCaches();
};
handleArticleDeleted = () => {
const {
article: articleData,
navigate,
categories,
rootCategoryId,
} = this.props;
const { navigate } = this.props;
const { article, categories, rootCategoryId } = this.state;
this.refreshSearchCaches();
const categoryId = articleData.categoryIds?.[0];
const categoryId = article?.categoryIds?.[0];
if (categories && rootCategoryId != null && categoryId != null) {
navigate(buildCategoryPath(categories, rootCategoryId, categoryId));
return;
@@ -46,19 +77,25 @@ class ArticleView extends Component {
navigate(defaultCategoryPath());
};
handleTabChange = (nextTab) => {
const { navigate } = this.props;
const { article } = this.state;
navigate(artikelDetailPath(article, nextTab));
};
render() {
const {
article: articleData,
tab,
onTabChange,
categories,
rootCategoryId,
} = this.props;
const { tab } = this.props;
const { article, categories, rootCategoryId } = this.state;
if (!article || categories == null || rootCategoryId == null) return null;
const resolvedTab = resolveArticleTab(tab, article);
if (tab !== resolvedTab) return null;
return (
<PanelTileGrid>
<ArticleViewName
article={articleData}
article={article}
categories={categories}
rootCategoryId={rootCategoryId}
onArticleUpdated={this.handleArticleUpdated}
@@ -68,24 +105,24 @@ class ArticleView extends Component {
wide={1}
tileKey={PANEL_TILE_KEYS.photo}
sx={{ minHeight: 0 }}
article={articleData}
article={article}
onArticleUpdated={this.handleArticleUpdated}
/>
<ArticleViewStock article={articleData} />
<ArticleViewStock article={article} />
<ArticleViewBrand
article={articleData}
article={article}
onArticleUpdated={this.handleArticleUpdated}
/>
<ArticleViewEANs
article={articleData}
article={article}
onArticleUpdated={this.handleArticleUpdated}
/>
<ArticleViewPrice
article={articleData}
article={article}
onArticleUpdated={this.handleArticleUpdated}
/>
@@ -93,13 +130,13 @@ class ArticleView extends Component {
wide={3}
tileKey={PANEL_TILE_KEYS.content}
minHeight={200}
article={articleData}
tab={tab}
onTabChange={onTabChange}
article={article}
tab={resolvedTab}
onTabChange={this.handleTabChange}
onArticleDeleted={this.handleArticleDeleted}
/>
<ArticleViewLists article={articleData} />
<ArticleViewLists article={article} />
</PanelTileGrid>
);
}