Remove context for state management

This commit is contained in:
Ariful Alam
2022-03-19 16:34:13 +06:00
parent b69ced8ce0
commit ab55fa68f1
13 changed files with 61 additions and 140 deletions

View File

@@ -1,8 +1,6 @@
import axios from 'axios'; import axios from 'axios';
import { Fragment, useCallback, useContext, useEffect, useState } from 'react'; import { Fragment, useCallback, useEffect, useState } from 'react';
import moment from 'moment'; import moment from 'moment';
import { ThemeContext } from './contexts/ThemeContext';
import { LoadingContext } from './contexts/LoadingContext';
import config from './ezprofile.config'; import config from './ezprofile.config';
import HeadTagEditor from './components/head-tag-editor'; import HeadTagEditor from './components/head-tag-editor';
import ErrorPage from './components/error-page'; import ErrorPage from './components/error-page';
@@ -14,10 +12,11 @@ import Experience from './components/experience';
import Education from './components/education'; import Education from './components/education';
import Project from './components/project'; import Project from './components/project';
import Blog from './components/blog'; import Blog from './components/blog';
import { getInitialTheme } from './helpers/utils';
function App() { function App() {
const { theme } = useContext(ThemeContext); const [theme, setTheme] = useState(getInitialTheme());
const { setLoading } = useContext(LoadingContext); const [loading, setLoading] = useState(true);
const [profile, setProfile] = useState(null); const [profile, setProfile] = useState(null);
const [repo, setRepo] = useState(null); const [repo, setRepo] = useState(null);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -108,7 +107,7 @@ function App() {
return ( return (
<Fragment> <Fragment>
<HeadTagEditor profile={profile} /> <HeadTagEditor profile={profile} theme={theme} />
<div className="fade-in h-screen"> <div className="fade-in h-screen">
{error ? ( {error ? (
<ErrorPage <ErrorPage
@@ -149,18 +148,24 @@ function App() {
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 rounded-box"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6 rounded-box">
<div className="col-span-1"> <div className="col-span-1">
<div className="grid grid-cols-1 gap-6"> <div className="grid grid-cols-1 gap-6">
{!config.themeConfig.disableSwitch && <ThemeChanger />} {!config.themeConfig.disableSwitch && (
<AvatarCard profile={profile} /> <ThemeChanger
<Details profile={profile} /> theme={theme}
<Skill /> setTheme={setTheme}
<Experience /> loading={loading}
<Education /> />
)}
<AvatarCard profile={profile} loading={loading} />
<Details profile={profile} loading={loading} />
<Skill loading={loading} />
<Experience loading={loading} />
<Education loading={loading} />
</div> </div>
</div> </div>
<div className="lg:col-span-2 col-span-1"> <div className="lg:col-span-2 col-span-1">
<div className="grid grid-cols-1 gap-6"> <div className="grid grid-cols-1 gap-6">
<Project repo={repo} /> <Project repo={repo} loading={loading} />
<Blog /> <Blog loading={loading} />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,16 +1,12 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useContext } from 'react';
import { LoadingContext } from '../../contexts/LoadingContext';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
import LazyImage from '../lazy-image'; import LazyImage from '../lazy-image';
const AvatarCard = (props) => { const AvatarCard = ({ profile, loading }) => {
const { loading } = useContext(LoadingContext);
return ( return (
<div className="card shadow-lg compact bg-base-100"> <div className="card shadow-lg compact bg-base-100">
<div className="grid place-items-center py-8"> <div className="grid place-items-center py-8">
{loading || !props.profile ? ( {loading || !profile ? (
<div className="avatar opacity-90"> <div className="avatar opacity-90">
<div className="mb-8 rounded-full w-32 h-32"> <div className="mb-8 rounded-full w-32 h-32">
{skeleton({ {skeleton({
@@ -25,10 +21,8 @@ const AvatarCard = (props) => {
<div className="mb-8 rounded-full w-32 h-32 ring ring-primary ring-offset-base-100 ring-offset-2"> <div className="mb-8 rounded-full w-32 h-32 ring ring-primary ring-offset-base-100 ring-offset-2">
{ {
<LazyImage <LazyImage
src={ src={profile.avatar ? profile.avatar : fallbackImage}
props.profile.avatar ? props.profile.avatar : fallbackImage alt={profile.name}
}
alt={props.profile.name}
placeholder={skeleton({ placeholder={skeleton({
width: 'w-full', width: 'w-full',
height: 'h-full', height: 'h-full',
@@ -41,16 +35,16 @@ const AvatarCard = (props) => {
)} )}
<div className="text-center mx-auto px-8"> <div className="text-center mx-auto px-8">
<h5 className="font-bold text-2xl"> <h5 className="font-bold text-2xl">
{loading || !props.profile ? ( {loading || !profile ? (
skeleton({ width: 'w-48', height: 'h-8' }) skeleton({ width: 'w-48', height: 'h-8' })
) : ( ) : (
<span className="opacity-70">{props.profile.name}</span> <span className="opacity-70">{profile.name}</span>
)} )}
</h5> </h5>
<div className="mt-3 text-base-content text-opacity-60"> <div className="mt-3 text-base-content text-opacity-60">
{loading || !props.profile {loading || !profile
? skeleton({ width: 'w-48', height: 'h-5' }) ? skeleton({ width: 'w-48', height: 'h-5' })
: props.profile.bio} : profile.bio}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,8 +1,7 @@
import { getDevtoArticle, getMediumArticle } from 'article-api'; import { getDevtoArticle, getMediumArticle } from 'article-api';
import moment from 'moment'; import moment from 'moment';
import { Fragment, useContext, useEffect, useState } from 'react'; import { Fragment, useEffect, useState } from 'react';
import { CgHashtag } from 'react-icons/cg'; import { CgHashtag } from 'react-icons/cg';
import { LoadingContext } from '../../contexts/LoadingContext';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
import { ga, skeleton } from '../../helpers/utils'; import { ga, skeleton } from '../../helpers/utils';
import LazyImage from '../lazy-image'; import LazyImage from '../lazy-image';
@@ -21,9 +20,8 @@ const displaySection = () => {
} }
}; };
const Blog = () => { const Blog = ({loading}) => {
const [articles, setArticles] = useState(null); const [articles, setArticles] = useState(null);
const { loading } = useContext(LoadingContext);
useEffect(() => { useEffect(() => {
if (displaySection()) { if (displaySection()) {

View File

@@ -12,8 +12,6 @@ import {
FaGlobe, FaGlobe,
} from 'react-icons/fa'; } from 'react-icons/fa';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useContext } from 'react';
import { LoadingContext } from '../../contexts/LoadingContext';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
@@ -31,9 +29,7 @@ const ListItem = ({ icon, title, value, link }) => {
); );
}; };
const Details = (props) => { const Details = ({ profile, loading }) => {
const { loading } = useContext(LoadingContext);
const renderSkeleton = () => { const renderSkeleton = () => {
let array = []; let array = [];
for (let index = 0; index < 4; index++) { for (let index = 0; index < 4; index++) {
@@ -53,22 +49,22 @@ const Details = (props) => {
return ( return (
<div className="card shadow-lg compact bg-base-100"> <div className="card shadow-lg compact bg-base-100">
<div className="card-body"> <div className="card-body">
{loading || !props.profile ? ( {loading || !profile ? (
renderSkeleton() renderSkeleton()
) : ( ) : (
<div className="bg-base-100 text-base-content text-opacity-60"> <div className="bg-base-100 text-base-content text-opacity-60">
{props.profile.location && ( {profile.location && (
<ListItem <ListItem
icon={<MdLocationOn className="mr-2" />} icon={<MdLocationOn className="mr-2" />}
title="Based on" title="Based on"
value={props.profile.location} value={profile.location}
/> />
)} )}
{props.profile.company && ( {profile.company && (
<ListItem <ListItem
icon={<FaBuilding className="mr-2" />} icon={<FaBuilding className="mr-2" />}
title="Company" title="Company"
value={props.profile.company} value={profile.company}
/> />
)} )}
<ListItem <ListItem
@@ -116,7 +112,7 @@ const Details = (props) => {
</div> </div>
)} )}
{/* <ul className="menu bg-base-100 text-base-content text-opacity-60"> {/* <ul className="menu bg-base-100 text-base-content text-opacity-60">
{loading || !props.profile ? ( {loading || !profile ? (
renderSkeleton() renderSkeleton()
) : ( ) : (
<> <>

View File

@@ -1,12 +1,8 @@
import { GoPrimitiveDot } from 'react-icons/go'; import { GoPrimitiveDot } from 'react-icons/go';
import { useContext } from 'react';
import { LoadingContext } from '../../contexts/LoadingContext';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
const Education = () => { const Education = ({ loading }) => {
const { loading } = useContext(LoadingContext);
const renderSkeleton = () => { const renderSkeleton = () => {
let array = []; let array = [];
for (let index = 0; index < 2; index++) { for (let index = 0; index < 2; index++) {

View File

@@ -1,12 +1,8 @@
import { GoPrimitiveDot } from 'react-icons/go'; import { GoPrimitiveDot } from 'react-icons/go';
import { useContext } from 'react';
import { LoadingContext } from '../../contexts/LoadingContext';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
const Experience = () => { const Experience = ({ loading }) => {
const { loading } = useContext(LoadingContext);
const renderSkeleton = () => { const renderSkeleton = () => {
let array = []; let array = [];
for (let index = 0; index < 2; index++) { for (let index = 0; index < 2; index++) {

View File

@@ -1,16 +1,13 @@
import { Fragment, useContext } from 'react'; import { Fragment } from 'react';
import { Helmet } from 'react-helmet-async'; import { Helmet } from 'react-helmet-async';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ThemeContext } from '../../contexts/ThemeContext';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
import { isThemeDarkish } from '../../helpers/utils'; import { isThemeDarkish } from '../../helpers/utils';
const HeadTagEditor = (props) => { const HeadTagEditor = ({ profile, theme }) => {
const { theme } = useContext(ThemeContext);
return ( return (
<Fragment> <Fragment>
{props.profile && ( {profile && (
<Helmet> <Helmet>
{config.googleAnalytics?.id && ( {config.googleAnalytics?.id && (
<script <script
@@ -26,20 +23,17 @@ const HeadTagEditor = (props) => {
gtag('config', '${config.googleAnalytics.id}');`} gtag('config', '${config.googleAnalytics.id}');`}
</script> </script>
)} )}
<title>Portfolio of {props.profile.name}</title> <title>Portfolio of {profile.name}</title>
<meta <meta
name="theme-color" name="theme-color"
content={isThemeDarkish(theme) ? '#000000' : '#ffffff'} content={isThemeDarkish(theme) ? '#000000' : '#ffffff'}
/> />
<meta name="description" content={props.profile.bio} /> <meta name="description" content={profile.bio} />
<meta <meta itemprop="name" content={`Portfolio of ${profile.name}`} />
itemprop="name" <meta itemprop="description" content={profile.bio} />
content={`Portfolio of ${props.profile.name}`} <meta itemprop="image" content={profile.avatar} />
/>
<meta itemprop="description" content={props.profile.bio} />
<meta itemprop="image" content={props.profile.avatar} />
<meta <meta
property="og:url" property="og:url"
@@ -50,20 +44,14 @@ const HeadTagEditor = (props) => {
} }
/> />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta <meta property="og:title" content={`Portfolio of ${profile.name}`} />
property="og:title" <meta property="og:description" content={profile.bio} />
content={`Portfolio of ${props.profile.name}`} <meta property="og:image" content={profile.avatar} />
/>
<meta property="og:description" content={props.profile.bio} />
<meta property="og:image" content={props.profile.avatar} />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta <meta name="twitter:title" content={`Portfolio of ${profile.name}`} />
name="twitter:title" <meta name="twitter:description" content={profile.bio} />
content={`Portfolio of ${props.profile.name}`} <meta name="twitter:image" content={profile.avatar} />
/>
<meta name="twitter:description" content={props.profile.bio} />
<meta name="twitter:image" content={props.profile.avatar} />
</Helmet> </Helmet>
)} )}
</Fragment> </Fragment>

View File

@@ -1,13 +1,10 @@
import { Fragment, useContext } from 'react'; import { Fragment } from 'react';
import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai'; import { AiOutlineStar, AiOutlineFork } from 'react-icons/ai';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { LoadingContext } from '../../contexts/LoadingContext';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
import { ga, languageColor, skeleton } from '../../helpers/utils'; import { ga, languageColor, skeleton } from '../../helpers/utils';
const Project = (props) => { const Project = ({ repo, loading }) => {
const { loading } = useContext(LoadingContext);
const renderSkeleton = () => { const renderSkeleton = () => {
let array = []; let array = [];
for (let index = 0; index < config.github.limit; index++) { for (let index = 0; index < config.github.limit; index++) {
@@ -55,7 +52,7 @@ const Project = (props) => {
}; };
const renderProjects = () => { const renderProjects = () => {
return props.repo.map((item, index) => ( return repo.map((item, index) => (
<div <div
className="card shadow-lg compact bg-base-100 cursor-pointer" className="card shadow-lg compact bg-base-100 cursor-pointer"
key={index} key={index}
@@ -163,7 +160,7 @@ const Project = (props) => {
</div> </div>
<div className="col-span-2"> <div className="col-span-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{loading || !props.repo ? renderSkeleton() : renderProjects()} {loading || !repo ? renderSkeleton() : renderProjects()}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,11 +1,7 @@
import { useContext } from 'react';
import { LoadingContext } from '../../contexts/LoadingContext';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
const Skill = () => { const Skill = ({ loading }) => {
const { loading } = useContext(LoadingContext);
const renderSkeleton = () => { const renderSkeleton = () => {
let array = []; let array = [];
for (let index = 0; index < 12; index++) { for (let index = 0; index < 12; index++) {

View File

@@ -1,16 +1,8 @@
import { AiOutlineControl } from 'react-icons/ai'; import { AiOutlineControl } from 'react-icons/ai';
import { useContext } from 'react';
import { ThemeContext } from '../../contexts/ThemeContext';
import { LoadingContext } from '../../contexts/LoadingContext';
import { skeleton } from '../../helpers/utils'; import { skeleton } from '../../helpers/utils';
import config from '../../ezprofile.config'; import config from '../../ezprofile.config';
const ThemeChanger = () => { const ThemeChanger = ({ theme, setTheme, loading }) => {
const { theme, setTheme } = useContext(ThemeContext);
const { loading } = useContext(LoadingContext);
console.log(theme);
const changeTheme = (e, selectedTheme) => { const changeTheme = (e, selectedTheme) => {
e.preventDefault(); e.preventDefault();
document.querySelector('html').setAttribute('data-theme', selectedTheme); document.querySelector('html').setAttribute('data-theme', selectedTheme);

View File

@@ -1,15 +0,0 @@
import { createContext, useState } from 'react';
const initialValue = true;
export const LoadingContext = createContext();
export const LoadingProvider = (props) => {
const [loading, setLoading] = useState(initialValue);
return (
<LoadingContext.Provider value={[loading, setLoading]}>
{props.children}
</LoadingContext.Provider>
);
};

View File

@@ -1,16 +0,0 @@
import { createContext, useState } from 'react';
import { getInitialTheme } from '../helpers/utils';
const initialValue = getInitialTheme();
export const ThemeContext = createContext();
export const ThemeProvider = (props) => {
const [theme, setTheme] = useState(initialValue);
return (
<ThemeContext.Provider value={[theme, setTheme]}>
{props.children}
</ThemeContext.Provider>
);
};

View File

@@ -2,19 +2,13 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import { ThemeProvider } from './contexts/ThemeContext';
import { LoadingProvider } from './contexts/LoadingContext';
import { HelmetProvider } from 'react-helmet-async'; import { HelmetProvider } from 'react-helmet-async';
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<ThemeProvider> <HelmetProvider>
<LoadingProvider> <App />
<HelmetProvider> </HelmetProvider>
<App />
</HelmetProvider>
</LoadingProvider>
</ThemeProvider>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById('root')
); );