BLOG-8 fix: circular dependency
All checks were successful
Frontend CI / build (push) Successful in 1m19s

This commit is contained in:
SquidSpirit 2025-01-18 19:49:57 +08:00
parent c2fef757b3
commit 018e037cf8
5 changed files with 80 additions and 92 deletions

View File

@ -1,10 +1,10 @@
"use client";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { Provider } from "react-redux";
import { useTagDispatch, useTagSelector } from "@/lib/home/presenter/tagHooks";
import { tagStartedAction, tagStoppedAction } from "@/lib/home/presenter/tagSlice";
import { useTagDispatch, useTagSelector } from "@/lib/home/presenter/tagHook";
import { tagShuffledAction } from "@/lib/home/presenter/tagReducer";
import tagStore from "@/lib/home/presenter/tagStore";
export default function SelfTags() {
@ -16,25 +16,35 @@ export default function SelfTags() {
}
function SelfTagsProvided() {
const tags = useTagSelector((state) => state.tag.tags);
const tags = useTagSelector((state) => state.tags);
const dispatch = useTagDispatch();
// Initialize with placeholder to prevent flickering
const [tagsToShow, setTagsToShow] = useState<string[]>([""]);
const [isTagsVisible, setIsTagsVisible] = useState(false);
const timer = useRef<NodeJS.Timeout | undefined>(undefined);
// On mount
useEffect(() => {
dispatch(tagStartedAction({ interval: 4000 }));
timer.current = setInterval(() => {
dispatch(tagShuffledAction());
}, 4000);
return () => {
dispatch(tagStoppedAction());
setIsTagsVisible(false);
clearInterval(timer.current);
timer.current = undefined;
};
}, [dispatch]);
// On tags changed
useEffect(() => {
if (tags.length === 0) return;
setIsTagsVisible(true);
setIsTagsVisible(false);
setTimeout(() => {
setIsTagsVisible(false);
}, 3500);
setTagsToShow(tags);
setIsTagsVisible(true);
}, 500);
}, [tags]);
return (
@ -43,7 +53,7 @@ function SelfTagsProvided() {
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-transparent via-60% to-white" />
<div className="flex flex-row items-center gap-x-2 overflow-hidden">
{tags.map((tag) => (
{tagsToShow.map((tag) => (
<Hashtag key={tag} tag={tag} />
))}
</div>

View File

@ -0,0 +1,55 @@
import { createAction, createReducer } from "@reduxjs/toolkit";
import shuffleArray from "@/lib/util/shuffleArray";
export const tagShuffledAction = createAction("tag/shuffled");
const tagReducer = createReducer<TagState>(
() => ({
tags: shuffleArray(tagsCollection),
}),
(builder) => {
builder.addCase(tagShuffledAction, (state) => {
state.tags = shuffleArray(tagsCollection);
});
},
);
export default tagReducer;
export type TagAction = ReturnType<typeof tagShuffledAction>;
export interface TagState {
tags: string[];
timer?: NodeJS.Timeout;
}
const tagsCollection = [
"APP",
"C++",
"Design Pattern",
"Docker",
"Flutter",
"Go",
"Java",
"LINER",
"Linux",
"Python",
"Squid",
"TypeScript",
"中央大學",
"全端",
"分享",
"前端",
"後端",
"教學",
"暴肝",
"知識",
"碼農",
"科技",
"科普",
"程式設計",
"資工系",
"軟體工程",
"遊戲",
"魷魚",
];

View File

@ -1,73 +0,0 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import tagStore from "@/lib/home/presenter/tagStore";
import shuffleArray from "@/lib/util/shuffleArray";
export interface TagState {
tags: string[];
timer?: NodeJS.Timeout;
}
export interface TagStartedActionPayload {
interval: number;
}
export const tagSlice = createSlice({
name: "tag",
initialState: {
tags: [],
timer: undefined,
} as TagState,
reducers: {
started: (state, action: PayloadAction<TagStartedActionPayload>) => {
state.tags = shuffleArray(tagsCollection);
state.timer = setInterval(() => {
tagStore.dispatch(tagSlice.actions.shuffled());
}, action.payload.interval);
},
shuffled: (state) => {
state.tags = shuffleArray(tagsCollection);
},
stopped: (state) => {
clearInterval(state.timer);
state.timer = undefined;
},
},
});
export const tagStartedAction = tagSlice.actions.started;
export const tagStoppedAction = tagSlice.actions.stopped;
const tagReducer = tagSlice.reducer;
export default tagReducer;
const tagsCollection = [
"APP",
"C++",
"Design Pattern",
"Docker",
"Flutter",
"Go",
"Java",
"LINER",
"Linux",
"Python",
"Squid",
"TypeScript",
"中央大學",
"全端",
"分享",
"前端",
"後端",
"教學",
"暴肝",
"知識",
"碼農",
"科技",
"科普",
"程式設計",
"資工系",
"軟體工程",
"遊戲",
"魷魚",
];

View File

@ -1,11 +1,7 @@
import { configureStore } from "@reduxjs/toolkit";
import tagReducer from "@/lib/home/presenter/tagSlice";
import tagReducer, { TagAction, TagState } from "@/lib/home/presenter/tagReducer";
const tagStore = configureStore({
reducer: {
tag: tagReducer,
},
export default configureStore<TagState, TagAction>({
reducer: tagReducer,
});
export default tagStore;