post api, redux optimization
This commit is contained in:
parent
0f31f32e5e
commit
69819cb908
|
|
@ -1,5 +1,12 @@
|
|||
// Types
|
||||
import { INewsScroll, INewsScrollAction } from "../types/store.types";
|
||||
import {
|
||||
INewsScroll,
|
||||
INewsScrollAction,
|
||||
IPostData,
|
||||
IPostDataAction,
|
||||
} from "../types/store.types";
|
||||
|
||||
// NewsScroll
|
||||
|
||||
export const setNewsScroll = (
|
||||
data: INewsScroll["data"]
|
||||
|
|
@ -7,3 +14,10 @@ export const setNewsScroll = (
|
|||
type: "SET_NEWS_SCROLL",
|
||||
payload: data,
|
||||
});
|
||||
|
||||
// Post
|
||||
|
||||
export const setPost = (data: IPostData["data"]): IPostDataAction => ({
|
||||
type: "SET_POST",
|
||||
payload: data,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { newsScrollParams } from "../../api/params";
|
|||
|
||||
// Types
|
||||
import { IPostsData } from "../../types/data.types";
|
||||
import { ILanguage, RootState } from "../../types/store.types";
|
||||
import { RootState } from "../../types/store.types";
|
||||
|
||||
// Actions
|
||||
import { setNewsScroll } from "../../actions/setData";
|
||||
|
|
@ -30,13 +30,13 @@ const NewsScroll = ({ title }: Props) => {
|
|||
const [lastLanguage, setLastLanguage] = useState<string>(language);
|
||||
|
||||
// redux
|
||||
const data = useSelector<RootState, RootState["dataReducer"]["data"]>(
|
||||
(state) => state.dataReducer.data
|
||||
const data = useSelector<RootState, RootState["newsScroll"]["data"]>(
|
||||
(state) => state.newsScroll.data
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (!(data[0].id > -1 && lastLanguage === language)) {
|
||||
if (!((data as IPostsData[])[0].id > -1 && lastLanguage === language)) {
|
||||
api.get(data, (data: IPostsData[]) => dispatch(setNewsScroll(data)));
|
||||
setLastLanguage(language);
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ const NewsScroll = ({ title }: Props) => {
|
|||
) : null}
|
||||
<div className="news-scroll-inner">
|
||||
{data ? (
|
||||
data.map((dataEl) => {
|
||||
(data as IPostsData[]).map((dataEl) => {
|
||||
return (
|
||||
<News
|
||||
key={uuidv4()}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// Modules
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
import { Navigation, Pagination, Autoplay } from 'swiper';
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import { Navigation, Pagination, Autoplay } from "swiper";
|
||||
|
||||
// Images
|
||||
import Placeholder from '../../assets/images/placeholder3.png';
|
||||
import Placeholder from "../../assets/images/placeholder3.png";
|
||||
|
||||
// Components
|
||||
import ContentItem from './ContentItem';
|
||||
import ContentItem from "./ContentItem";
|
||||
|
||||
// Static
|
||||
import { titlePlaceholder } from './MainContent';
|
||||
import { titlePlaceholder } from "./MainContent";
|
||||
|
||||
const ContentSlider = () => {
|
||||
return (
|
||||
|
|
@ -24,8 +24,10 @@ const ContentSlider = () => {
|
|||
}}
|
||||
modules={[Navigation, Pagination, Autoplay]}
|
||||
pagination={{
|
||||
type: 'bullets',
|
||||
}}>
|
||||
type: "bullets",
|
||||
clickable: true,
|
||||
}}
|
||||
>
|
||||
<SwiperSlide>
|
||||
<ContentItem type="big" img={Placeholder} title={titlePlaceholder} />
|
||||
</SwiperSlide>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,12 @@ import { LazyLoadImage } from "react-lazy-load-image-component";
|
|||
|
||||
interface IProps {
|
||||
img: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const NewsArticleImg = ({ img, title }: IProps) => {
|
||||
const NewsArticleImg = ({ img }: IProps) => {
|
||||
return (
|
||||
<div className={"news-article-image"}>
|
||||
<LazyLoadImage src={img} alt="" effect="blur" useIntersectionObserver />
|
||||
<div className="swiper-lazy-preloader"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
// Modules
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import { Navigation, Pagination, Autoplay } from "swiper";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// Components
|
||||
import NewsArticleImg from "./NewsArticleImg";
|
||||
|
||||
// Images
|
||||
import Placeholder from "../../assets/images/placeholder3.png";
|
||||
import { IPostData } from "../../types/store.types";
|
||||
|
||||
import { titlePlaceholder } from "../main/MainContent";
|
||||
interface IProps {
|
||||
images: IPostData["data"]["data"]["featured_images"];
|
||||
}
|
||||
|
||||
const NewsArticleSlider = () => {
|
||||
const NewsArticleSlider = ({ images }: IProps) => {
|
||||
return (
|
||||
<div className="news-article-slider">
|
||||
<Swiper
|
||||
|
|
@ -24,20 +26,14 @@ const NewsArticleSlider = () => {
|
|||
modules={[Navigation, Pagination, Autoplay]}
|
||||
pagination={{
|
||||
type: "bullets",
|
||||
clickable: true,
|
||||
}}
|
||||
>
|
||||
<SwiperSlide>
|
||||
<NewsArticleImg img={Placeholder} title={titlePlaceholder} />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide>
|
||||
<NewsArticleImg img={Placeholder} title={titlePlaceholder} />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide>
|
||||
<NewsArticleImg img={Placeholder} title={titlePlaceholder} />
|
||||
</SwiperSlide>
|
||||
<SwiperSlide>
|
||||
<NewsArticleImg img={Placeholder} title={titlePlaceholder} />
|
||||
{images.map((img) => (
|
||||
<SwiperSlide key={uuidv4()}>
|
||||
<NewsArticleImg img={img.path} />
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,75 +1,93 @@
|
|||
// Modules
|
||||
import { LazyLoadImage } from "react-lazy-load-image-component";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// Components
|
||||
import Aside from "../components/aside/Aside";
|
||||
import NewsArticleSlider from "../components/news/NewsArticleSlider";
|
||||
|
||||
// Images
|
||||
import placeholder from "../assets/images/placeholder3.png";
|
||||
import Loader from "../components/global/Loader";
|
||||
|
||||
// Icons
|
||||
import { ReactComponent as Share } from "../assets/icons/share.svg";
|
||||
|
||||
// Types
|
||||
import { RootState } from "../types/store.types";
|
||||
import { IPostData } from "../types/store.types";
|
||||
|
||||
// Actions
|
||||
import { setPost } from "../actions/setData";
|
||||
|
||||
// Api
|
||||
import { Api } from "../api/Api";
|
||||
import { url } from "../url";
|
||||
|
||||
const NewsArticle = () => {
|
||||
const { id } = useParams();
|
||||
|
||||
// api
|
||||
const api = new Api(`${url}/posts/${id}`);
|
||||
|
||||
const language = api.language;
|
||||
const [lastLanguage, setLastLanguage] = useState<string>(language);
|
||||
|
||||
// redux
|
||||
const data = useSelector<RootState, RootState["post"]["data"]>(
|
||||
(state) => state.post.data
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!(data.data.id === parseInt(id as string) && lastLanguage === language)
|
||||
) {
|
||||
api.get(data, (data: IPostData["data"]) => dispatch(setPost(data)));
|
||||
setLastLanguage(language);
|
||||
}
|
||||
}, [language, lastLanguage]);
|
||||
|
||||
return (
|
||||
<div className="news-article">
|
||||
<div className="container">
|
||||
<div className="news-article-inner">
|
||||
{data.data.id > -1 ? (
|
||||
<div className="news-article-content">
|
||||
<div className="news-article-info">
|
||||
<div className="news-article-status">
|
||||
<h3 className="news-article-category">Спорт</h3>
|
||||
<h3 className="news-article-date">15:23, 21 января 2023</h3>
|
||||
<div className="news-article-left">
|
||||
{data.data.categories.map((category) => (
|
||||
<Link
|
||||
key={uuidv4()}
|
||||
to={`/category/${category.id}`}
|
||||
className="news-article-category"
|
||||
>
|
||||
{category.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<h2 className="news-article-title">
|
||||
В федерации футбола Туркменистана подвели итоги прошедшего года
|
||||
и наметили курс на 2023 год
|
||||
</h2>
|
||||
<div className="news-article-right">
|
||||
<h3 className="news-article-date">
|
||||
{data.data.published_at}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="news-article-title">{data.data.title}</h2>
|
||||
</div>
|
||||
<div className="news-article-slider-wrapper">
|
||||
<NewsArticleSlider />
|
||||
<NewsArticleSlider images={data.data.featured_images} />
|
||||
</div>
|
||||
<p className="news-article-text">
|
||||
Lorem ipsum dolor sit amet consectetur. Vestibulum eget elementum
|
||||
urna tincidunt diam commodo mauris ac sodales. Lorem ipsum dolor
|
||||
sit amet consectetur. Lorem ipsum dolor sit amet consectetur.
|
||||
Lorem ipsum dolor sit amet consectetur. Vestibulum eget elementum
|
||||
urna tincidunt diam commodo mauris ac sodales. Lorem ipsum dolor
|
||||
sit amet consectetur. <br />
|
||||
<br /> Lorem ipsum dolor sit amet consectetur. Lorem ipsum dolor
|
||||
sit amet consectetur. Vestibulum eget elementum urna tincidunt
|
||||
diam commodo mauris ac sodales. Lorem ipsum dolor sit amet
|
||||
consectetur. Lorem ipsum dolor sit amet consectetur. Lorem ipsum
|
||||
dolor sit amet consectetur. Vestibulum eget elementum urna
|
||||
tincidunt diam commodo mauris ac sodales.
|
||||
<br />
|
||||
<br /> Lorem ipsum dolor sit amet consectetur. Vestibulum eget
|
||||
elementum urna tincidunt diam commodo mauris ac sodales. Lorem
|
||||
ipsum dolor sit amet consectetur. Lorem ipsum dolor sit amet
|
||||
consectetur. Lorem ipsum dolor sit amet consectetur.
|
||||
<br />
|
||||
<br /> Vestibulum eget elementum urna tincidunt diam commodo
|
||||
mauris ac sodales. Lorem ipsum dolor sit amet consectetur. Lorem
|
||||
ipsum dolor sit amet consectetur. Lorem ipsum dolor sit amet
|
||||
consectetur. Vestibulum eget elementum urna tincidunt diam commodo
|
||||
mauris ac sodales.
|
||||
<br />
|
||||
<br /> Lorem ipsum dolor sit amet consectetur. Vestibulum eget
|
||||
elementum urna tincidunt diam commodo mauris ac sodales. Lorem
|
||||
ipsum dolor sit amet consectetur. Lorem ipsum dolor sit amet
|
||||
consectetur. Lorem ipsum dolor sit amet consectetur.
|
||||
<br />
|
||||
<br /> Vestibulum eget elementum urna tincidunt diam commodo
|
||||
mauris ac sodales. Lorem ipsum dolor sit amet consectetur. Lorem
|
||||
ipsum dolor sit amet consectetur. Lorem ipsum dolor sit amet
|
||||
consectetur. Vestibulum eget elementum urna tincidunt diam commodo
|
||||
mauris ac sodales.
|
||||
</p>
|
||||
<p
|
||||
className="news-article-text"
|
||||
dangerouslySetInnerHTML={{ __html: data.data.content_html }}
|
||||
></p>
|
||||
<button className="share-btn">
|
||||
<Share /> <span>Поделиться</span>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
<Aside />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
// Types
|
||||
import { INewsScroll, INewsScrollAction } from "../types/store.types";
|
||||
import {
|
||||
INewsScroll,
|
||||
INewsScrollAction,
|
||||
IPostData,
|
||||
IPostDataAction,
|
||||
} from "../types/store.types";
|
||||
|
||||
export const postsInitialState = {
|
||||
export const newsScrollInitialState = {
|
||||
data: [
|
||||
{
|
||||
id: -1,
|
||||
|
|
@ -46,8 +51,8 @@ export const postsInitialState = {
|
|||
],
|
||||
};
|
||||
|
||||
export const dataReducer = (
|
||||
state: INewsScroll = postsInitialState,
|
||||
export const newsScrollReducer = (
|
||||
state: INewsScroll = newsScrollInitialState,
|
||||
action: INewsScrollAction
|
||||
) => {
|
||||
switch (action.type) {
|
||||
|
|
@ -59,3 +64,62 @@ export const dataReducer = (
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const postInitialState = {
|
||||
data: {
|
||||
data: {
|
||||
id: -1,
|
||||
title: "",
|
||||
slug: "",
|
||||
excerpt: "",
|
||||
published_at: "",
|
||||
featured_images: [
|
||||
{
|
||||
id: -1,
|
||||
disk_name: "",
|
||||
file_name: "",
|
||||
path: "",
|
||||
extension: "",
|
||||
},
|
||||
{
|
||||
id: -1,
|
||||
disk_name: "",
|
||||
file_name: "",
|
||||
path: "",
|
||||
extension: "",
|
||||
},
|
||||
{
|
||||
id: -1,
|
||||
disk_name: "",
|
||||
file_name: "",
|
||||
path: "",
|
||||
extension: "",
|
||||
},
|
||||
],
|
||||
content_html: "",
|
||||
categories: [
|
||||
{
|
||||
id: -1,
|
||||
name: "",
|
||||
},
|
||||
],
|
||||
powerseo_title: "",
|
||||
powerseo_description: "",
|
||||
powerseo_keywords: "",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const postReducer = (
|
||||
state: IPostData = postInitialState,
|
||||
action: IPostDataAction
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case "SET_POST": {
|
||||
return { ...state, data: action.payload };
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
|||
// Reducers
|
||||
import { activeLinkReducer } from "../reducers/activeLink.reducer";
|
||||
import { languageReducer } from "../reducers/language.reducer";
|
||||
import { dataReducer } from "../reducers/dataReducer";
|
||||
import { newsScrollReducer, postReducer } from "../reducers/dataReducer";
|
||||
|
||||
export const allReducers = combineReducers({
|
||||
activeLink: activeLinkReducer,
|
||||
language: languageReducer,
|
||||
dataReducer,
|
||||
newsScroll: newsScrollReducer,
|
||||
post: postReducer,
|
||||
});
|
||||
|
||||
export const functionalityStore = configureStore({
|
||||
|
|
|
|||
|
|
@ -20,7 +20,14 @@
|
|||
|
||||
.news-article-status {
|
||||
display: flex;
|
||||
gap: 3.2rem;
|
||||
gap: 2.4rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.news-article-left {
|
||||
display: flex;
|
||||
gap: 2.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
|
@ -47,6 +54,7 @@
|
|||
}
|
||||
|
||||
.news-article-image {
|
||||
min-height: 30rem;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { allReducers } from "../store/functionality";
|
|||
// Types
|
||||
import { IPostsData } from "./data.types";
|
||||
|
||||
// NavLink
|
||||
export interface ActiveLinkType {
|
||||
active: number;
|
||||
}
|
||||
|
|
@ -12,6 +13,7 @@ export interface ActiveLinkActionType {
|
|||
payload: number;
|
||||
}
|
||||
|
||||
// Language
|
||||
export interface ILanguage {
|
||||
title: "RU" | "EN" | "TM";
|
||||
}
|
||||
|
|
@ -21,6 +23,8 @@ export interface ILanguageAction {
|
|||
payload: "RU" | "EN" | "TM";
|
||||
}
|
||||
|
||||
// NewsScroll
|
||||
|
||||
export interface INewsScroll {
|
||||
data: IPostsData[];
|
||||
}
|
||||
|
|
@ -29,6 +33,19 @@ export interface INewsScrollAction {
|
|||
payload: INewsScroll["data"];
|
||||
}
|
||||
|
||||
// Post
|
||||
|
||||
export interface IPostData {
|
||||
data: {
|
||||
data: IPostsData;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IPostDataAction {
|
||||
type: "SET_POST";
|
||||
payload: IPostData["data"];
|
||||
}
|
||||
|
||||
// ALL TYPES BEFORE THIS LINE ==================
|
||||
|
||||
export type RootState = ReturnType<typeof allReducers>;
|
||||
|
|
|
|||
Loading…
Reference in New Issue