Feat: moved to zustand from redux

This commit is contained in:
2025-01-10 11:07:22 +03:00
parent f35bb1d8dd
commit 3260e0403e
8 changed files with 51 additions and 84 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -11,10 +11,9 @@
}, },
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
"@reduxjs/toolkit": "^2.5.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-redux": "^9.2.0" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",

View File

@@ -1,9 +1,9 @@
import { useEffect, useRef } from 'react'; import { useRef } from 'react';
import { useShallow } from 'zustand/shallow';
import './App.scss'; import './App.scss';
import { TierImage } from './components/Image'; import { TierImage } from './components/Image';
import { Tier, TierProps } from './components/Tier'; import { Tier, TierProps } from './components/Tier';
import { useAppDispatch, useAppSelector } from './hooks'; import useStore from './store';
import { addTierImage } from './store';
const default_tier_levels: TierProps[] = [ const default_tier_levels: TierProps[] = [
{ {
@@ -30,11 +30,7 @@ interface tierImage {
} }
function App() { function App() {
const images = useAppSelector(state => state.tierImages); const [images, addTierImage] = useStore(useShallow(state => [state.images, state.addTierImage]));
const dispatch = useAppDispatch();
useEffect(() => {
console.log(images);
}, [images]);
const uploadBtn = useRef<HTMLInputElement>(null); const uploadBtn = useRef<HTMLInputElement>(null);
@@ -49,7 +45,7 @@ function App() {
const handleAdd = (images: tierImage[]) => { const handleAdd = (images: tierImage[]) => {
images.forEach(image => { images.forEach(image => {
dispatch(addTierImage(image)); addTierImage(image);
}); });
}; };

View File

@@ -1,3 +1,4 @@
import { useDraggable } from '@dnd-kit/core';
import { tierImage } from '../store'; import { tierImage } from '../store';
import './Image.scss'; import './Image.scss';
interface ImageProps { interface ImageProps {
@@ -5,14 +6,22 @@ interface ImageProps {
onDragStart?: () => void; onDragStart?: () => void;
} }
export const TierImage = ({ image, onDragStart }: ImageProps) => { export const TierImage = ({ image }: ImageProps) => {
const { attributes, listeners, setNodeRef, transform } = useDraggable({
id: `draggable:${image.name}`,
});
const style = transform
? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
}
: undefined;
return ( return (
<div <div
className='flex flex-wrap justify-center gap-4 mr-1 anime-container' className='flex flex-wrap justify-center gap-4 mr-1 anime-container'
onDragStart={() => { {...listeners}
// e.preventDefault(); {...attributes}
if (onDragStart) onDragStart(); ref={setNodeRef}
}} style={style}
> >
<div className={`w-[calc(10rem*.5625)] h-40 relative`}> <div className={`w-[calc(10rem*.5625)] h-40 relative`}>
<img src={image.url} alt={image.name} className='h-full w-full object-cover' /> <img src={image.url} alt={image.name} className='h-full w-full object-cover' />

View File

@@ -1,6 +1,4 @@
import { useState } from 'react'; import useStore from '../store';
import { useAppDispatch, useAppSelector } from '../hooks';
import { changeTierImage, tierImage } from '../store';
import { TierImage } from './Image'; import { TierImage } from './Image';
export interface TierProps { export interface TierProps {
@@ -11,8 +9,7 @@ export interface TierProps {
export const Tier = ({ color, name, textColor }: TierProps) => { export const Tier = ({ color, name, textColor }: TierProps) => {
let color_code = ''; let color_code = '';
let text_color_code = ''; let text_color_code = '';
const tierImages = useAppSelector(state => state.tierImages); const tierImages = useStore(state => state.images);
const dispatch = useAppDispatch();
switch (color) { switch (color) {
case 'green': case 'green':
color_code = '#00b894'; color_code = '#00b894';
@@ -34,31 +31,9 @@ export const Tier = ({ color, name, textColor }: TierProps) => {
text_color_code = '#2d3436'; text_color_code = '#2d3436';
} }
const [currentDragImage, setCurrentDragImage] = useState<tierImage | null>(null);
const [currentDragTier, setCurrentDragTier] = useState<string>('');
const onDragStart = (image: tierImage) => {
setCurrentDragImage(image);
};
return ( return (
<> <>
<div <div className='w-full min-h-40 bg-[#2d3436] h-auto flex flex-row'>
className='w-full min-h-40 bg-[#2d3436] h-auto flex flex-row'
onDragEnd={() => {
// e.preventDefault();
if (currentDragImage) {
if (currentDragImage.category === name) return;
console.log(currentDragImage);
console.log(name);
dispatch(changeTierImage({ ...currentDragImage, category: name }));
}
setCurrentDragImage(null);
}}
onDragOver={() => {
if (currentDragTier !== name) setCurrentDragTier(name);
}}
>
<div <div
className='w-24 min-h-40 flex items-center justify-center' className='w-24 min-h-40 flex items-center justify-center'
style={{ style={{
@@ -72,7 +47,7 @@ export const Tier = ({ color, name, textColor }: TierProps) => {
{tierImages {tierImages
.filter(image => image.category === name) .filter(image => image.category === name)
.map((image, index) => ( .map((image, index) => (
<TierImage image={image} key={index} onDragStart={() => onDragStart(image)} /> <TierImage image={image} key={index} />
))} ))}
</div> </div>
</div> </div>

View File

@@ -1,5 +0,0 @@
import { useDispatch, useSelector } from 'react-redux';
import { AppDispatch, RootState } from './store';
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();

View File

@@ -1,14 +1,13 @@
import { DndContext } from '@dnd-kit/core';
import { StrictMode } from 'react'; import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App.tsx'; import App from './App.tsx';
import './index.scss'; import './index.scss';
import store from './store.ts';
createRoot(document.getElementById('root')!).render( createRoot(document.getElementById('root')!).render(
<StrictMode> <StrictMode>
<Provider store={store}> <DndContext>
<App /> <App />
</Provider> </DndContext>
</StrictMode>, </StrictMode>,
); );

View File

@@ -1,4 +1,5 @@
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit'; import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
export interface tierImage { export interface tierImage {
name: string; name: string;
@@ -6,34 +7,27 @@ export interface tierImage {
category: string; category: string;
} }
const tierImages = createSlice({ interface tierStore {
name: 'images', images: tierImage[];
initialState: [] as tierImage[], addTierImage: (image: tierImage) => void;
reducers: { editTierImage: (image: tierImage, tier: string) => void;
addTierImage: (state, action: PayloadAction<tierImage>) => { removeTierImage: (image: tierImage) => void;
state.push(action.payload); }
},
removeTierImage: (state, action: PayloadAction<string>) => {
return state.filter(image => image.name !== action.payload);
},
changeTierImage: (state, action: PayloadAction<tierImage>) => {
return state.map(image => {
if (image.name == action.payload.name) return action.payload;
return image;
});
},
},
});
export const { addTierImage, removeTierImage, changeTierImage } = tierImages.actions; const useStore = create(
devtools<tierStore>(
const store = configureStore({ set => ({
reducer: { images: [] as tierImage[],
tierImages: tierImages.reducer, addTierImage: (image: tierImage) => set(state => ({ images: [...state.images, image] })),
editTierImage: (image: tierImage, tier: string) =>
set(state => ({ images: state.images.map(i => (i.name === image.name ? { ...i, category: tier } : i)) })),
removeTierImage: (image: tierImage) => {
URL.revokeObjectURL(image.url);
set(state => ({ images: state.images.filter(i => i.name !== image.name) }));
}, },
}); }),
{ name: 'tierStore' },
),
);
export type RootState = ReturnType<typeof store.getState>; export default useStore;
export type AppDispatch = typeof store.dispatch;
export default store;