Refactor Skills
component: improve data loading logic with useCallback
, add error handling, update UI styles, and enhance state management.
This commit is contained in:
@@ -1,53 +1,72 @@
|
|||||||
import {useEffect, useState} from 'react';
|
import {useCallback, useEffect, useState} from 'react';
|
||||||
import type {CharacterData} from '@/types/CharacterJson.ts';
|
import type {CharacterData} from '@/types/CharacterJson.ts';
|
||||||
import {loadSkillsWithValues, type SkillWithValue} from '@/utils/loaders.ts';
|
import {loadSkillsWithValues, type SkillWithValue} from '@/utils/loaders.ts';
|
||||||
|
|
||||||
export default function Skills({jsonData}: { jsonData: CharacterData }) {
|
export default function Skills({jsonData}: { jsonData: CharacterData }) {
|
||||||
const [skills, setSkills] = useState<SkillWithValue[]>([]);
|
const [skills, setSkills] = useState<SkillWithValue[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const resetToDefaults = useCallback(() => {
|
||||||
let isMounted = true;
|
setSkills([]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = useCallback(async (signal: AbortSignal) => {
|
||||||
try {
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
// Load skills with their values using the new loader function
|
// Load skills with their values using the new loader function
|
||||||
const loadedSkills = await loadSkillsWithValues(jsonData.talents);
|
const loadedSkills = await loadSkillsWithValues(jsonData.talents);
|
||||||
|
|
||||||
if (isMounted) {
|
// Check if component is still mounted and request wasn't cancelled
|
||||||
setSkills(loadedSkills);
|
if (signal.aborted) return;
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading skills:', error);
|
|
||||||
if (isMounted) {
|
|
||||||
setError('Failed to load skills. Please try again.');
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadData();
|
setSkills(loadedSkills);
|
||||||
|
} catch (err) {
|
||||||
|
if (signal.aborted) return;
|
||||||
|
|
||||||
|
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
||||||
|
console.error('Error loading skills:', errorMessage);
|
||||||
|
setError('Failed to load skills. Please try again.');
|
||||||
|
|
||||||
|
// Reset to default values on error
|
||||||
|
resetToDefaults();
|
||||||
|
} finally {
|
||||||
|
if (!signal.aborted) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [jsonData.talents, resetToDefaults]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
loadData(abortController.signal);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
isMounted = false;
|
abortController.abort();
|
||||||
};
|
};
|
||||||
}, [jsonData.talents]);
|
}, [loadData]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading skills...</div>;
|
return <div className="animate-pulse">Loading skills...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <div className="text-red-500">{error}</div>;
|
return (
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
||||||
|
Error loading skills: {error}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skills.length === 0) {
|
if (skills.length === 0) {
|
||||||
return <div>No skills found.</div>;
|
return <div>No skills found.</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(jsonData);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<h1 className="text-2xl font-bold mb-4">Skills</h1>
|
<h1 className="text-2xl font-bold mb-4">Skills</h1>
|
||||||
@@ -56,7 +75,9 @@ export default function Skills({jsonData}: { jsonData: CharacterData }) {
|
|||||||
<div key={skill.id} className="border p-3 rounded shadow">
|
<div key={skill.id} className="border p-3 rounded shadow">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<h2 className="text-lg font-semibold">{skill.name}</h2>
|
<h2 className="text-lg font-semibold">{skill.name}</h2>
|
||||||
<span className="bg-blue-100 text-blue-800 font-bold px-2 py-1 rounded">
|
<span
|
||||||
|
className="bg-blue-100 text-blue-800 font-bold px-2 py-1 rounded flex items-center justify-center"
|
||||||
|
style={{width: '2.5em'}}>
|
||||||
{skill.value}
|
{skill.value}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,12 +91,12 @@ export default function Skills({jsonData}: { jsonData: CharacterData }) {
|
|||||||
{/* </ul>*/}
|
{/* </ul>*/}
|
||||||
{/* </div>*/}
|
{/* </div>*/}
|
||||||
{/*)}*/}
|
{/*)}*/}
|
||||||
{/*{skill.tools && (*/}
|
{skill.tools && (
|
||||||
{/* <div className="mt-2">*/}
|
<div className="mt-2">
|
||||||
{/* <h3 className="font-medium">Tools:</h3>*/}
|
<h3 className="font-medium">Tools:</h3>
|
||||||
{/* <p className="text-sm">{skill.tools}</p>*/}
|
<p className="text-sm">{skill.tools}</p>
|
||||||
{/* </div>*/}
|
</div>
|
||||||
{/*)}*/}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user