This is a solution to the REST Countries API with color theme switcher challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
Users should be able to:
- See all countries from the API on the homepage
- Search for a country using an
input
field - Filter countries by region
- Click on a country to see more detailed information on a separate page
- Click through to the border countries on the detail page
- Toggle the color scheme between light and dark mode
- Solution URL: https://www.frontendmentor.io/solutions/responsive-spa-using-react-and-redux-toolkit-with-sass-grid-and-flexbox--0LLHhBFa-
- Live Site URL: https://rest-countries-kv.netlify.app/
- Semantic HTML5 markup
- CSS custom properties
- Flexbox
- CSS Grid
- Desktop-first workflow
- React - JS library
- Redux Toolkit - State Manager
- React Router - For Routes
- Axios - For HTTP requests
- Sass - CSS pre-processor
I've learned lot of things in this challenge:
- How to use Redux toolkit for state management
// store/theme.js
import { createSlice } from '@reduxjs/toolkit';
const themeSlice = createSlice({
name: 'theme',
initialState: {
isDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
},
reducers: {
toggle(state) {
state.isDark = !state.isDark;
document.querySelector('body').classList.toggle('dark-theme');
},
},
});
const { reducer: themeReducer, actions: themeActions } = themeSlice;
export { themeReducer as default, themeActions };
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import themeReducer from './theme';
const store = configureStore({
reducer: {
theme: themeReducer,
filterRegion: filterRegionReducer,
countries: countriesReducer,
search: searchReducer,
},
});
export default store;
// index.js
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
// Uses | components/SearchBar
import { useDispatch, useSelector } from 'react-redux';
import { countriesActions } from '../../store/countries';
import { searchActions } from '../../store/search';
const SearchBar = () => {
const isDark = useSelector(state => state.theme.isDark);
const search = useSelector(state => state.search.value);
const { searchCountry } = countriesActions;
const { setSearch } = searchActions;
const dispatch = useDispatch();
const searchChangeHandler = e => {
dispatch(setSearch(e.target.value));
if (e.target.value.trim() === '') {
return;
}
dispatch(searchCountry(e.target.value.trim()));
};
return (
<Card className="search-bar">
{isDark || <ion-icon name="search-sharp" />}
{isDark && <ion-icon name="search-sharp" className="dark" />}
<input
className="search-bar__input"
type="text"
name="search"
placeholder="Search for a country..."
value={search}
onChange={searchChangeHandler}
/>
</Card>
);
};
- How to work with custom hooks
// hooks/use-https
import axios from 'axios';
import { useCallback, useState } from 'react';
const useHttp = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const sendRequest = useCallback(async (url, callback) => {
setIsLoading(true);
setError(null);
try {
const res = await axios.get(url);
callback(res.data);
} catch (err) {
setError({ ...err, message: err.message || 'Something went wrong!' });
}
setIsLoading(false);
}, []);
return { isLoading, error, sendRequest };
};
- How to use react router
const App = () => {
return (
<div className="App">
<Header />
<Routes>
<Route path="/" element={<AllCountries />} />
<Route path=":countryId" element={<Country />} />
<Route path="*" element={<NotFound />} />
</Routes>
<Footer />
</div>
);
};
- How to use lazy loading
import React, { Suspense } from 'react';
// Loaded only when these routes are visited
const NotFound = React.lazy(() => import('./pages/NotFound'));
const App = () => {
return (
<div className="App">
<Header />
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
<Footer />
</div>
);
};
- How to make dark themes in React with Sass
@mixin dark-theme {
--color-bg: #202c37;
--color-primary: #2b3945;
--color-grey: #cbd5e1;
--color-text: #ffffff;
}
@mixin light-theme {
--color-bg: #fafafa;
--color-primary: #ffffff;
--color-grey: #64748b;
--color-text: #111517;
}
:root {
// Theme
@include light-theme;
}
@media (prefers-color-scheme: dark) {
:root {
@include dark-theme;
}
.dark-theme {
@include light-theme;
}
}
Technologies I'd be learning soon:
- NextJs
- Typescript
- Testing (JS)
- Blockchain Development
- Flutter & Dart
- Cyber Security
- MDN Docs - This is an amazing reference which helped me finally understand detailed concepts like data- attr, aria attr, input range etc.
- W3Schools - This is an amazing website for learning, I've learned about semantic tags from here only and learned many important HTML elements. I'd recommend it to anyone still learning this concept.
- React Router Docs - Best reference to get start with React Router
- Github - @vatsalsinghkv
- Twitter - @vatsalsinghkv
- Instagram - @vatsal.sing.hkv
- Facebook - @vatsalsinghkv
- Frontend Mentor - @vatsalsinghkv