Skip to content

Commit 715de97

Browse files
committed
Refactor context to use SWR for data fetching and improve bookmark management
1 parent 229ae6b commit 715de97

File tree

1 file changed

+93
-82
lines changed

1 file changed

+93
-82
lines changed

‎src/Context.jsx‎

Lines changed: 93 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,124 @@
1-
import React, { useEffect,useContext,useReducer, useState } from 'react';
1+
import React, { useEffect, useContext, useReducer, useState, useCallback, useMemo } from 'react';
2+
import useSWR from 'swr';
23
import reducer from './reducer';
3-
// Context created
4-
let API="https://hn.algolia.com/api/v1/search?";
5-
6-
const initialState = {
7-
isLoading:true,
8-
query:" ",
9-
nbPages:0,
10-
page:0,
11-
hits:[],
12-
popularNews:[],
4+
// Base API endpoint
5+
const API = "https://hn.algolia.com/api/v1/search?";
6+
7+
// Initial state
8+
const initialState = {
9+
isLoading: true,
10+
query: " ",
11+
nbPages: 0,
12+
page: 0,
13+
hits: [],
14+
popularNews: [],
1315
};
1416
const AppContext = React.createContext();
15-
// Now the provider function
17+
18+
// Fetcher function for SWR caching
19+
const fetcher = (url) => fetch(url).then(res => res.json());
20+
1621
const AppProvider = ({ children }) => {
17-
const [state,dispatch]=useReducer(reducer,initialState);
22+
const [state, dispatch] = useReducer(reducer, initialState);
1823
const [showPopularNews, setShowPopularNews] = useState(false);
1924
const [bookMark, setBookMark] = useState([]);
20-
21-
22-
const fetchApiData= async (url)=>{
23-
24-
dispatch({type:"SET_LOADING"});
25-
try{
26-
const res= await fetch(url);
27-
const data = await res.json();
28-
console.log(data);
29-
dispatch({type:"GET_STORIES",
30-
payload:{
31-
hits:data.hits,
32-
nbPages:data.nbPages,
25+
26+
// API fetching with caching
27+
const { data, error } = useSWR(`${API}query=${state.query}&page=${state.page}`, fetcher);
28+
29+
// Handle API response
30+
useEffect(() => {
31+
if (data) {
32+
dispatch({
33+
type: "GET_STORIES",
34+
payload: {
35+
hits: data.hits,
36+
nbPages: data.nbPages,
3337
}
34-
})
35-
36-
}
37-
catch(error){
38-
console.log(error);
39-
}
40-
};
41-
const fetchPopularNews = async () => {
42-
try {
43-
dispatch({type:"SET_LOADING"});
44-
const res = await fetch(`${API}query=technology&tags=story`);
45-
const data = await res.json();
46-
47-
const sortedNews = data.hits
48-
.filter((item) => item.num_comments)
49-
.sort((a, b) => (b.num_comments || 0) - (a.num_comments || 0));
38+
});
39+
}
40+
if (error) {
41+
console.error("Error fetching data:", error);
42+
}
43+
}, [data, error]);
44+
45+
// Fetch popular news separately with SWR
46+
const { data: popularData, error: popularError } = useSWR(`${API}query=technology&tags=story`, fetcher);
47+
48+
useEffect(() => {
49+
if (popularData) {
50+
const sortedNews = popularData.hits
51+
.filter((item) => item.num_comments)
52+
.sort((a, b) => (b.num_comments || 0) - (a.num_comments || 0))
53+
.slice(0, 7);
5054

5155
dispatch({
5256
type: "GET_POPULAR_NEWS",
53-
payload: sortedNews.slice(0, 7),
57+
payload: sortedNews,
5458
});
55-
56-
} catch (error) {
57-
console.log(error);
5859
}
59-
};
60-
61-
62-
const searchFn= (searchQuery) =>{
63-
dispatch({type:"SEARCH_QUERY",
64-
payload:searchQuery,
65-
});
66-
};
67-
const getNextPage=()=>{
68-
dispatch({
69-
type:"NEXT_PAGE",
70-
})
71-
}
72-
const getPrevPage=()=>{
73-
dispatch({
74-
type:"PREV_PAGE",
75-
})
76-
}
60+
}, [popularData, popularError]);
61+
62+
// Efficient pagination handlers
63+
const getNextPage = useCallback(() => {
64+
dispatch({ type: "NEXT_PAGE" });
65+
}, []);
7766

78-
const addBookMark = (news) => {
67+
const getPrevPage = useCallback(() => {
68+
dispatch({ type: "PREV_PAGE" });
69+
}, []);
70+
71+
// Memoized bookmark management
72+
const addBookMark = useCallback((news) => {
7973
const newBookMark = [...bookMark, news];
8074
setBookMark(newBookMark);
8175
localStorage.setItem('bookmarks', JSON.stringify(newBookMark));
82-
}
76+
}, [bookMark]);
8377

84-
useEffect(()=>{
85-
fetchApiData(`${API}query=${state.query}&{state.page}`);
86-
},[state.query,state.page]);
78+
// Remove bookmark function
79+
const removeBookMark = useCallback((news) => {
80+
const updatedBookmarks = bookMark.filter((item) => item.objectID !== news.objectID);
81+
setBookMark(updatedBookmarks);
82+
localStorage.setItem('bookmarks', JSON.stringify(updatedBookmarks));
83+
}, [bookMark]);
8784

85+
// Load bookmarks from localStorage on initial render
8886
useEffect(() => {
89-
fetchPopularNews();
87+
const storedData = localStorage.getItem('bookmarks');
88+
if (storedData) {
89+
setBookMark(JSON.parse(storedData));
90+
}
9091
}, []);
9192

92-
useEffect(() => {
93-
let storedData = localStorage.getItem('bookmarks')
94-
if(storedData){
95-
setBookMark(JSON.parse(storedData))
96-
}
97-
},[])
93+
// Memoize values for better performance
94+
const value = useMemo(() => ({
95+
...state,
96+
searchFn: (query) => dispatch({ type: "SEARCH_QUERY", payload: query }),
97+
getNextPage,
98+
getPrevPage,
99+
showPopularNews,
100+
setShowPopularNews,
101+
addBookMark,
102+
removeBookMark,
103+
bookMark,
104+
setBookMark,
105+
}), [state, showPopularNews, bookMark, addBookMark, removeBookMark]);
106+
107+
// Display error fallback
108+
if (error || popularError) {
109+
return <h1>Error loading data. Please try again later.</h1>;
110+
}
98111

99-
100112
return (
101-
<AppContext.Provider value={{...state,searchFn,getNextPage,getPrevPage,showPopularNews,setShowPopularNews,addBookMark,bookMark,setBookMark}}>
113+
<AppContext.Provider value={value}>
102114
{children}
103115
</AppContext.Provider>
104116
);
105117
};
106118

107-
108-
const useGlobalContext =()=>
109-
{
119+
// Custom hook for accessing context
120+
const useGlobalContext = () => {
110121
return useContext(AppContext);
111122
};
112123

113-
export { AppContext, AppProvider,useGlobalContext };
124+
export { AppContext, AppProvider, useGlobalContext };

0 commit comments

Comments
 (0)