feat: implement SkillContext for optimized data fetching

This commit is contained in:
Shivansh Gupta
2026-03-04 23:29:01 +05:30
parent 159d04c9bf
commit 45bda8009f
2 changed files with 80 additions and 1 deletions

View File

@@ -0,0 +1,76 @@
import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';
import type { Skill, StarMap } from '../types';
import { supabase } from '../lib/supabase';
interface SkillContextType {
skills: Skill[];
stars: StarMap;
loading: boolean;
refreshSkills: () => Promise<void>;
}
const SkillContext = createContext<SkillContextType | undefined>(undefined);
export function SkillProvider({ children }: { children: React.ReactNode }) {
const [skills, setSkills] = useState<Skill[]>([]);
const [stars, setStars] = useState<StarMap>({});
const [loading, setLoading] = useState(true);
const fetchSkillsAndStars = useCallback(async (silent = false) => {
if (!silent) setLoading(true);
try {
// Fetch skills index
const res = await fetch('/skills.json');
const data = await res.json();
setSkills(data);
// Fetch stars from Supabase if available
if (supabase) {
const { data: starData, error } = await supabase
.from('skill_stars')
.select('skill_id, star_count');
if (!error && starData) {
const starMap: StarMap = {};
starData.forEach((item: { skill_id: string; star_count: number }) => {
starMap[item.skill_id] = item.star_count;
});
setStars(starMap);
}
}
} catch (err) {
console.error('SkillContext: Failed to load skills', err);
} finally {
if (!silent) setLoading(false);
}
}, []);
useEffect(() => {
fetchSkillsAndStars();
}, [fetchSkillsAndStars]);
const refreshSkills = useCallback(async () => {
await fetchSkillsAndStars(true);
}, [fetchSkillsAndStars]);
const value = useMemo(() => ({
skills,
stars,
loading,
refreshSkills
}), [skills, stars, loading, refreshSkills]);
return (
<SkillContext.Provider value={value}>
{children}
</SkillContext.Provider>
);
}
export function useSkills() {
const context = useContext(SkillContext);
if (context === undefined) {
throw new Error('useSkills must be used within a SkillProvider');
}
return context;
}

View File

@@ -2,6 +2,7 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
import { SkillProvider } from './context/SkillContext';
const rootElement = document.getElementById('root');
if (!rootElement) {
@@ -10,6 +11,8 @@ if (!rootElement) {
createRoot(rootElement).render(
<StrictMode>
<App />
<SkillProvider>
<App />
</SkillProvider>
</StrictMode>,
);