Improved loading content of and article with saving them in redux store
When article was loaded once than it will be cached in redux store. On the next loading of article content it will be get from store
This commit is contained in:
parent
335218fdd9
commit
fecce76fe1
47
Dockerfile
47
Dockerfile
@ -1,30 +1,43 @@
|
|||||||
# Install dependencies only when needed
|
# Install dependencies of project
|
||||||
FROM node:fermium-alpine AS deps
|
FROM node:fermium-alpine AS dependencies
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
WORKDIR /home/app/
|
WORKDIR /home/app/
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json ./
|
||||||
RUN npm ci
|
RUN npm i
|
||||||
|
|
||||||
|
|
||||||
# Bundle static assets with nginx
|
# Build application to bunch of static files
|
||||||
FROM node:fermium-alpine as production
|
FROM node:fermium-alpine AS builder
|
||||||
|
|
||||||
# Copy built assets from builder
|
|
||||||
WORKDIR /home/app/
|
WORKDIR /home/app/
|
||||||
COPY --from=deps ./home/app/node_modules ./node_modules
|
COPY --from=dependencies ./home/app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
|
# NGINX image
|
||||||
|
FROM nginx:1.21.6 as production
|
||||||
|
# Copy built assets from builder
|
||||||
|
COPY --from=builder /home/app/build /usr/share/nginx/html
|
||||||
|
# Add nginx.config
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
# Copy setup nginx entrypoint file
|
||||||
|
COPY ./scripts/entrypoint.sh .
|
||||||
|
|
||||||
# Expose ports
|
# Expose ports
|
||||||
EXPOSE 3000
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Execute script
|
||||||
|
RUN chmod +x ./entrypoint.sh
|
||||||
|
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV production
|
||||||
ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
|
# ENV USER_NAME=node_user USER_UID=2000 GROUP_NAME=node_group GROUP_UID=2000
|
||||||
|
|
||||||
RUN deluser --remove-home node \
|
# RUN deluser --remove-home node \
|
||||||
&& addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \
|
# && addgroup --g ${GROUP_UID} -S ${GROUP_NAME} \
|
||||||
&& adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}
|
# && adduser -D -S -s /sbin/nologin -u ${USER_UID} -G ${GROUP_NAME} ${USER_NAME}
|
||||||
USER "${USER_NAME}"
|
# USER "${USER_NAME}"
|
||||||
|
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
|
|
||||||
ENTRYPOINT [ "npm","start"]
|
# Start serving
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
@ -1,6 +1,9 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
# no verbose
|
# no verbose
|
||||||
set +x
|
set +x
|
||||||
|
# save env to file
|
||||||
|
printenv > .env.production
|
||||||
|
|
||||||
# config
|
# config
|
||||||
envFilename='.env.production'
|
envFilename='.env.production'
|
||||||
resolvingPath='/usr/share/nginx/html'
|
resolvingPath='/usr/share/nginx/html'
|
||||||
|
@ -1,44 +1,30 @@
|
|||||||
import type { ArticleStore } from "../domain/articleStore";
|
import type { ArticleStore } from "../domain/articleStore";
|
||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
import { getArticle } from "article/data/articleAPIService";
|
|
||||||
import { Article } from "article/domain/articleEntity";
|
import { Article } from "article/domain/articleEntity";
|
||||||
|
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
|
||||||
|
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
function useArticleViewModel(
|
function useArticleViewModel(
|
||||||
store: ArticleStore,
|
store: ArticleStore,
|
||||||
fetchArticleUseCase: (
|
fetchArticleUseCase: FetchArticleUseCase,
|
||||||
fetchArticleCallback: (id: string) => Promise<Article | null>,
|
getArticleUseCase: GetArticleUseCase,
|
||||||
setArticle: ArticleStore["setArticle"],
|
|
||||||
id: string,
|
|
||||||
) => Promise<Article | null>,
|
|
||||||
getArticleUseCase: (
|
|
||||||
getArticle: ArticleStore["getArticle"],
|
|
||||||
setArticle: ArticleStore["setArticle"],
|
|
||||||
id: Article["id"],
|
|
||||||
) => Promise<Article | null>,
|
|
||||||
id: string,
|
|
||||||
) {
|
) {
|
||||||
let article: Article | null | undefined;
|
const { id } = useParams();
|
||||||
|
|
||||||
const _getArticle = useCallback(
|
const getArticle = useCallback(
|
||||||
(id: string) => {
|
() => {
|
||||||
getArticleUseCase(store.getArticle, store.setArticle, id).then(async (value) => {
|
getArticleUseCase.call(id ?? '').catch((_) => fetchArticleUseCase.call(id ?? ''));
|
||||||
if (value == null) {
|
console.log(id);
|
||||||
article = await fetchArticleUseCase(getArticle, store.setArticle, id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
article = value;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[store.setArticle]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(getArticle, []);
|
||||||
_getArticle(id);
|
|
||||||
}, [article]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
article: store.article,
|
article: store.currentArticle,
|
||||||
shouldShowLoading: typeof store.article === "undefined" || store.isLoading,
|
shouldShowLoading: store.isLoading,
|
||||||
hasError: store.hasError,
|
hasError: store.hasError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { integratorApiClient } from "core/httpClient";
|
|||||||
|
|
||||||
const articleEndpoint = "/papers/"
|
const articleEndpoint = "/papers/"
|
||||||
|
|
||||||
async function getArticle(id: string): Promise<Article> {
|
async function fetchArticle(id: string): Promise<Article> {
|
||||||
try {
|
try {
|
||||||
const response = await integratorApiClient.get<FetchArticleByIdDTO>(
|
const response = await integratorApiClient.get<FetchArticleByIdDTO>(
|
||||||
// `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
|
// `https://run.mocky.io/v3/62cd4581-d864-4d46-b1d6-02b45b5d1994/${id}`
|
||||||
@ -33,4 +33,4 @@ async function getArticle(id: string): Promise<Article> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getArticle };
|
export { fetchArticle };
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
import type { Article } from "../domain/articleEntity";
|
import type { Article } from "../domain/articleEntity";
|
||||||
import { getArticle as getArticleAPI } from "./articleAPIService";
|
|
||||||
import * as actionTypes from "./articleActionTypes";
|
import * as actionTypes from "./articleActionTypes";
|
||||||
import { dispatchStatus } from "../../store/index";
|
import { dispatchStatus } from "../../store/index";
|
||||||
|
|
||||||
const setArticleAction = (article: Article) => (dispatch: any) =>
|
const setArticleAction = (article: Article, articlesList: Array<Article>) => (dispatch: any) => {
|
||||||
dispatch({ type: actionTypes.SET_ARTICLE, article });
|
if (!articlesList.includes(article)) {
|
||||||
|
const updatedList = articlesList.concat([article]);
|
||||||
|
dispatch({ type: actionTypes.SET_ARTICLE, article, updatedList });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getArticleAction = (id: string) => (dispatch: any) => {
|
const getArticleAction = (id: string, articles: Array<Article>) => (dispatch: any) => {
|
||||||
|
const filteredArray = articles.filter((e) => e.id == id);
|
||||||
return getArticleAPI(id)
|
if (filteredArray.length > 0) {
|
||||||
.then((article) => {
|
const article = filteredArray[0];
|
||||||
dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch);
|
dispatchStatus(actionTypes.GET_ARTICLE, ".success", article)(dispatch);
|
||||||
return article;
|
return article;
|
||||||
})
|
}
|
||||||
.catch((reason) => {
|
|
||||||
|
const reason = 'Article not in the store';
|
||||||
dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch);
|
dispatchStatus(actionTypes.GET_ARTICLE, ".failure", reason)(dispatch);
|
||||||
return reason;
|
return null;
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { setArticleAction, getArticleAction };
|
export { setArticleAction, getArticleAction };
|
||||||
|
@ -2,37 +2,58 @@ import React, { useCallback, useState } from "react";
|
|||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { ArticleStore } from "../domain/articleStore";
|
import { ArticleStore } from "../domain/articleStore";
|
||||||
import type { Article } from "../domain/articleEntity";
|
import type { Article } from "../domain/articleEntity";
|
||||||
import { getArticle as getArticleAPI } from "./articleAPIService";
|
|
||||||
|
|
||||||
const useArticleCommonStore = (): ArticleStore => {
|
const useArticleCommonStore = (): ArticleStore => {
|
||||||
const [isLoading, setLoading] = useState<boolean>(false);
|
const [isLoading, setLoading] = useState<boolean>(false);
|
||||||
const [hasError, setError] = useState<boolean>(false);
|
const [hasError, setError] = useState<boolean>(false);
|
||||||
const [article, setArticleState] = useState<Article | undefined>();
|
const [currentArticle, setCurrentArticle] = useState<Article | null>(null);
|
||||||
|
const [articles, setArticlesState] = useState<Array<Article>>([]);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const getArticle = useCallback(
|
const getArticle = useCallback(
|
||||||
async (id: string) => {
|
(id: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
if (typeof currentArticle === undefined) {
|
||||||
const article = await getArticleAPI(id);
|
const fromStore = findArticleFromStore(id);
|
||||||
setArticleState(article);
|
if (typeof fromStore === undefined) {
|
||||||
setLoading(false);
|
|
||||||
return article;
|
|
||||||
} catch (error) {
|
|
||||||
setError(true);
|
setError(true);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
setLoading(false);
|
||||||
|
setCurrentArticle(fromStore);
|
||||||
|
return fromStore;
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
return currentArticle;
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const findArticleFromStore = (id: string): Article | null => {
|
||||||
|
const filteredArray = articles.filter((e) => e.id == id);
|
||||||
|
if (filteredArray.length > 0) {
|
||||||
|
return filteredArray[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const setNewArticle = (newArticle: Article) => {
|
||||||
|
setCurrentArticle(newArticle);
|
||||||
|
if (!articles.includes(newArticle)) {
|
||||||
|
setArticlesState(articles.concat([newArticle]));
|
||||||
|
} else if (articles.length == 0) {
|
||||||
|
setArticlesState([newArticle]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
article: article,
|
articles: articles,
|
||||||
|
currentArticle: currentArticle,
|
||||||
isLoading,
|
isLoading,
|
||||||
hasError,
|
hasError,
|
||||||
setArticle: setArticleState,
|
setArticle: setNewArticle,
|
||||||
getArticle,
|
getArticle: getArticle,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@ import * as actionTypes from "./articleActionTypes";
|
|||||||
type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">;
|
type ArticleStoreState = Omit<ArticleStore, "getArticle" | "setArticle">;
|
||||||
|
|
||||||
const INITIAL_STATE: ArticleStoreState = {
|
const INITIAL_STATE: ArticleStoreState = {
|
||||||
article: undefined,
|
articles: [],
|
||||||
|
currentArticle: null,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
hasError: false,
|
hasError: false,
|
||||||
};
|
};
|
||||||
@ -16,11 +17,11 @@ const articleReducer = (
|
|||||||
): ArticleStoreState => {
|
): ArticleStoreState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actionTypes.SET_ARTICLE:
|
case actionTypes.SET_ARTICLE:
|
||||||
return { ...state, article: action.article };
|
return { ...state, articles: action.updatedList, currentArticle: action.article };
|
||||||
case actionTypes.GET_ARTICLE:
|
case actionTypes.GET_ARTICLE:
|
||||||
return { ...state, isLoading: true };
|
return { ...state, isLoading: true };
|
||||||
case actionTypes.GET_ARTICLE_SUCCESS:
|
case actionTypes.GET_ARTICLE_SUCCESS:
|
||||||
return { ...state, isLoading: false, article: action.payload };
|
return { ...state, isLoading: false, currentArticle: action.payload };
|
||||||
case actionTypes.GET_ARTICLE_FAILURE:
|
case actionTypes.GET_ARTICLE_FAILURE:
|
||||||
return { ...state, hasError: true, isLoading: false };
|
return { ...state, hasError: true, isLoading: false };
|
||||||
default:
|
default:
|
||||||
|
@ -9,22 +9,23 @@ import { RootState, useAppSelector } from "store";
|
|||||||
const articleSelector = (state: RootState): ArticleStoreState => state.article;
|
const articleSelector = (state: RootState): ArticleStoreState => state.article;
|
||||||
|
|
||||||
const useArticleStore = (): ArticleStore => {
|
const useArticleStore = (): ArticleStore => {
|
||||||
const { isLoading, article, hasError } = useAppSelector(articleSelector);
|
const { isLoading, hasError, currentArticle, articles } = useAppSelector(articleSelector);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const setArticle = useCallback(
|
const setArticle = useCallback(
|
||||||
(article: Article) => setArticleAction(article)(dispatch),
|
(article: Article) => setArticleAction(article, articles)(dispatch),
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getArticle = useCallback(
|
const getArticle = useCallback(
|
||||||
(id: string) => getArticleAction(id)(dispatch),
|
(id: string) => getArticleAction(id, articles)(dispatch),
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
article: article,
|
articles: articles,
|
||||||
|
currentArticle: currentArticle,
|
||||||
isLoading,
|
isLoading,
|
||||||
hasError,
|
hasError,
|
||||||
setArticle,
|
setArticle,
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { Article } from './articleEntity';
|
import { Article } from './articleEntity';
|
||||||
interface ArticleStore {
|
interface ArticleStore {
|
||||||
// State
|
// State
|
||||||
article: Article | undefined;
|
articles: Array<Article>;
|
||||||
|
currentArticle: Article | null;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
hasError: boolean;
|
hasError: boolean;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
setArticle(article?: Article): void;
|
setArticle(article: Article): void;
|
||||||
getArticle(identifier: string): Promise<Article | null>;
|
getArticle(identifier: string): Article | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { ArticleStore };
|
export type { ArticleStore };
|
||||||
|
@ -1,6 +1,32 @@
|
|||||||
import { Article } from "article/domain/articleEntity";
|
import { Article } from "article/domain/articleEntity";
|
||||||
import { ArticleStore } from "article/domain/articleStore";
|
import { ArticleStore } from "article/domain/articleStore";
|
||||||
|
|
||||||
|
|
||||||
|
class FetchArticleUseCase {
|
||||||
|
/* ------------------------------ Dependencies ------------------------------ */
|
||||||
|
_fetchArticleCallback: (id: string) => Promise<Article | null>;
|
||||||
|
_store: ArticleStore;
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
constructor(
|
||||||
|
fetchArticle: (id: string) => Promise<Article | null>,
|
||||||
|
store: ArticleStore,
|
||||||
|
) {
|
||||||
|
this._fetchArticleCallback = fetchArticle;
|
||||||
|
this._store = store;
|
||||||
|
}
|
||||||
|
/* ----------------------------- Implementation ----------------------------- */
|
||||||
|
async call(id: string): Promise<Article | null> {
|
||||||
|
return this._fetchArticleCallback(id).then((article) => {
|
||||||
|
if (article != null) {
|
||||||
|
this._store.setArticle(article);
|
||||||
|
}
|
||||||
|
return article;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const fetchArticleUseCase = async (
|
const fetchArticleUseCase = async (
|
||||||
fetchArticleCallback: (id: string) => Promise<Article | null>,
|
fetchArticleCallback: (id: string) => Promise<Article | null>,
|
||||||
setArticle: ArticleStore["setArticle"],
|
setArticle: ArticleStore["setArticle"],
|
||||||
@ -12,5 +38,5 @@ const fetchArticleUseCase = async (
|
|||||||
}
|
}
|
||||||
return article;
|
return article;
|
||||||
};
|
};
|
||||||
|
export { FetchArticleUseCase };
|
||||||
export { fetchArticleUseCase };
|
export { fetchArticleUseCase };
|
||||||
|
@ -1,6 +1,28 @@
|
|||||||
import { Article } from "article/domain/articleEntity";
|
import { Article } from "article/domain/articleEntity";
|
||||||
import type { ArticleStore } from "../domain/articleStore";
|
import type { ArticleStore } from "../domain/articleStore";
|
||||||
|
|
||||||
|
class GetArticleUseCase {
|
||||||
|
/* ------------------------------ Dependencies ------------------------------ */
|
||||||
|
_store: ArticleStore;
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
constructor(
|
||||||
|
store: ArticleStore,
|
||||||
|
) {
|
||||||
|
this._store = store;
|
||||||
|
}
|
||||||
|
/* ----------------------------- Implementation ----------------------------- */
|
||||||
|
async call(id: string): Promise<Article> {
|
||||||
|
const storedArticle = this._store.getArticle(id);
|
||||||
|
if (storedArticle != null) {
|
||||||
|
this._store.setArticle(storedArticle);
|
||||||
|
return storedArticle;
|
||||||
|
}
|
||||||
|
throw new Error('Article not found');
|
||||||
|
}
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const getArticleUseCase = async (
|
const getArticleUseCase = async (
|
||||||
getArticle: ArticleStore["getArticle"],
|
getArticle: ArticleStore["getArticle"],
|
||||||
setArticle: ArticleStore["setArticle"],
|
setArticle: ArticleStore["setArticle"],
|
||||||
@ -13,4 +35,5 @@ const getArticleUseCase = async (
|
|||||||
return article;
|
return article;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { GetArticleUseCase };
|
||||||
export { getArticleUseCase };
|
export { getArticleUseCase };
|
||||||
|
@ -10,27 +10,20 @@ import { SVGSearch } from "components/icons";
|
|||||||
import BaseLayout from "components/BaseLayout";
|
import BaseLayout from "components/BaseLayout";
|
||||||
import Typography from "components/typography/Typography";
|
import Typography from "components/typography/Typography";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { fetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
|
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
|
||||||
import { getArticleUseCase } from "article/useCases/getArticleUseCase";
|
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
|
||||||
|
import { fetchArticle } from "article/data/articleAPIService";
|
||||||
|
|
||||||
const AnArticle = () => {
|
const AnArticle = () => {
|
||||||
const store = useArticleStore();
|
const store = useArticleStore();
|
||||||
const { id } = useParams();
|
|
||||||
const { article, hasError, shouldShowLoading } = useArticleViewModel(
|
const { article, hasError, shouldShowLoading } = useArticleViewModel(
|
||||||
store,
|
store,
|
||||||
fetchArticleUseCase,
|
new FetchArticleUseCase(fetchArticle, store),
|
||||||
getArticleUseCase,
|
new GetArticleUseCase(store),
|
||||||
id ?? '',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { i18n, t } = useTranslation();
|
const { i18n, t } = useTranslation();
|
||||||
|
|
||||||
// const { id } = useParams();
|
|
||||||
// const newId = `${id}`;
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// store.getArticle(newId);
|
|
||||||
// }, [id]);
|
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return <NotFound />;
|
return <NotFound />;
|
||||||
}
|
}
|
||||||
|
@ -13,21 +13,17 @@ import BaseLayout from "components/BaseLayout";
|
|||||||
import Container from "components/Container";
|
import Container from "components/Container";
|
||||||
import NotFound from "./NotFound";
|
import NotFound from "./NotFound";
|
||||||
import Markdown from "components/Markdown";
|
import Markdown from "components/Markdown";
|
||||||
import { fetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
|
import { FetchArticleUseCase } from "article/useCases/fetchArticleUseCase";
|
||||||
import { getArticleUseCase } from "article/useCases/getArticleUseCase";
|
import { GetArticleUseCase } from "article/useCases/getArticleUseCase";
|
||||||
|
import { fetchArticle } from "article/data/articleAPIService";
|
||||||
|
|
||||||
const AnArticleBody = () => {
|
const AnArticleBody = () => {
|
||||||
const store = useArticleStore();
|
const store = useArticleStore();
|
||||||
const { id } = useParams();
|
|
||||||
const { article, hasError, shouldShowLoading } = useArticleViewModel(
|
const { article, hasError, shouldShowLoading } = useArticleViewModel(
|
||||||
store,
|
store,
|
||||||
fetchArticleUseCase,
|
new FetchArticleUseCase(fetchArticle, store),
|
||||||
getArticleUseCase,
|
new GetArticleUseCase(store),
|
||||||
id ?? '',
|
|
||||||
);
|
);
|
||||||
// useEffect(() => {
|
|
||||||
// store.getArticle(newId);
|
|
||||||
// }, [id]);
|
|
||||||
if (hasError) <NotFound />;
|
if (hasError) <NotFound />;
|
||||||
return (
|
return (
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user