- memoize all components

- implement metadata context
This commit is contained in:
Amruth Pillai
2020-07-09 14:00:18 +05:30
parent 9e98da038c
commit 3aaef5f730
71 changed files with 489 additions and 396 deletions

View File

@ -1,8 +1,16 @@
import firebase from 'gatsby-plugin-firebase';
import { debounce } from 'lodash';
import React, { createContext, useContext, useEffect, useState } from 'react';
import React, {
createContext,
memo,
useContext,
useEffect,
useState,
} from 'react';
import UserContext from './UserContext';
const DEBOUNCE_WAIT_TIME = 4000;
const defaultState = {
isOffline: false,
isUpdating: false,
@ -10,7 +18,8 @@ const defaultState = {
getResumes: async () => {},
createResume: () => {},
updateResume: async () => {},
debouncedUpdate: async () => {},
debouncedUpdateResume: async () => {},
debouncedUpdateMetadata: async () => {},
deleteResume: () => {},
};
@ -77,7 +86,23 @@ const DatabaseProvider = ({ children }) => {
setUpdating(false);
};
const debouncedUpdate = debounce(updateResume, 2000);
const debouncedUpdateResume = debounce(updateResume, DEBOUNCE_WAIT_TIME);
const updateMetadata = async (resumeId, metadata) => {
setUpdating(true);
await firebase
.database()
.ref(`users/${user.uid}/resumes/${resumeId}`)
.update({
metadata,
updatedAt: firebase.database.ServerValue.TIMESTAMP,
});
setUpdating(false);
};
const debouncedUpdateMetadata = debounce(updateMetadata, DEBOUNCE_WAIT_TIME);
const deleteResume = (id) => {
firebase.database().ref(`users/${user.uid}/resumes/${id}`).remove();
@ -91,7 +116,8 @@ const DatabaseProvider = ({ children }) => {
getResume,
createResume,
updateResume,
debouncedUpdate,
debouncedUpdateResume,
debouncedUpdateMetadata,
deleteResume,
}}
>
@ -102,4 +128,6 @@ const DatabaseProvider = ({ children }) => {
export default DatabaseContext;
export { DatabaseProvider };
const memoizedProvider = memo(DatabaseProvider);
export { memoizedProvider as DatabaseProvider };

View File

@ -0,0 +1,70 @@
import { clone, setWith } from 'lodash';
import React, {
createContext,
memo,
useCallback,
useContext,
useReducer,
} from 'react';
import leftSections from '../data/leftSections';
import DatabaseContext from './DatabaseContext';
import { useSelector as useResumeSelector } from './ResumeContext';
const initialState = {
template: 'Onyx',
font: 'Montserrat',
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
colors: {
textColor: '#444444',
primaryColor: '#5875DB',
backgroundColor: '#FFFFFF',
},
};
const MetadataContext = createContext({});
const MetadataProvider = ({ children }) => {
const id = useResumeSelector((state) => state.id);
const { debouncedUpdateMetadata } = useContext(DatabaseContext);
const memoizedReducer = useCallback(
(state, { type, payload }) => {
let newState;
switch (type) {
case 'set_layout':
newState = setWith(clone(state), 'layout', payload, clone);
debouncedUpdateMetadata(id, newState);
return newState;
default:
throw new Error();
}
},
[id, debouncedUpdateMetadata],
);
const [state, dispatch] = useReducer(memoizedReducer, initialState);
const selectValue = (callback) => callback(state);
return (
<MetadataContext.Provider value={{ selectValue, dispatch }}>
{children}
</MetadataContext.Provider>
);
};
const useSelector = (callback) => {
const { selectValue } = useContext(MetadataContext);
return selectValue(callback);
};
const useDispatch = () => {
const { dispatch } = useContext(MetadataContext);
return dispatch;
};
const memoizedProvider = memo(MetadataProvider);
export { memoizedProvider as MetadataProvider, useSelector, useDispatch };

View File

@ -1,5 +1,5 @@
import { createNanoEvents } from 'nanoevents';
import React, { createContext } from 'react';
import React, { createContext, memo } from 'react';
import ModalEvents from '../constants/ModalEvents';
const emitter = createNanoEvents();
@ -18,4 +18,6 @@ const ModalProvider = ({ children }) => {
export default ModalContext;
export { ModalProvider };
const memoizedProvider = memo(ModalProvider);
export { memoizedProvider as ModalProvider };

View File

@ -2,6 +2,7 @@ import arrayMove from 'array-move';
import { clone, findIndex, get, setWith } from 'lodash';
import React, {
createContext,
memo,
useCallback,
useContext,
useReducer,
@ -10,10 +11,10 @@ import DatabaseContext from './DatabaseContext';
const initialState = {};
const ResumeContext = createContext(initialState);
const ResumeContext = createContext({});
const ResumeProvider = ({ children }) => {
const { debouncedUpdate } = useContext(DatabaseContext);
const { debouncedUpdateResume } = useContext(DatabaseContext);
const memoizedReducer = useCallback(
(state, { type, payload }) => {
@ -31,7 +32,7 @@ const ResumeProvider = ({ children }) => {
[...items, payload.value],
clone,
);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'on_edit_item':
@ -44,7 +45,7 @@ const ResumeProvider = ({ children }) => {
payload.value,
clone,
);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'on_delete_item':
@ -52,7 +53,7 @@ const ResumeProvider = ({ children }) => {
index = findIndex(items, ['id', payload.value.id]);
items.splice(index, 1);
newState = setWith(clone(state), payload.path, items, clone);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'on_move_item_up':
@ -60,7 +61,7 @@ const ResumeProvider = ({ children }) => {
index = findIndex(items, ['id', payload.value.id]);
items = arrayMove(items, index, index - 1);
newState = setWith(clone(state), payload.path, items, clone);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'on_move_item_down':
@ -68,12 +69,12 @@ const ResumeProvider = ({ children }) => {
index = findIndex(items, ['id', payload.value.id]);
items = arrayMove(items, index, index + 1);
newState = setWith(clone(state), payload.path, items, clone);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'on_input':
newState = setWith(clone(state), payload.path, payload.value, clone);
debouncedUpdate(newState);
debouncedUpdateResume(newState);
return newState;
case 'set_data':
@ -83,7 +84,7 @@ const ResumeProvider = ({ children }) => {
throw new Error();
}
},
[debouncedUpdate],
[debouncedUpdateResume],
);
const [state, dispatch] = useReducer(memoizedReducer, initialState);
@ -107,4 +108,6 @@ const useDispatch = () => {
return dispatch;
};
export { ResumeProvider, useSelector, useDispatch };
const memoizedProvider = memo(ResumeProvider);
export { memoizedProvider as ResumeProvider, useSelector, useDispatch };

View File

@ -1,5 +1,5 @@
import firebase from 'gatsby-plugin-firebase';
import React, { createContext, useContext, useRef } from 'react';
import React, { createContext, memo, useContext, useRef } from 'react';
import { toast } from 'react-toastify';
import { isFileImage } from '../utils';
import { useDispatch, useSelector } from './ResumeContext';
@ -84,4 +84,6 @@ const StorageProvider = ({ children }) => {
export default StorageContext;
export { StorageProvider };
const memoizedProvider = memo(StorageProvider);
export { memoizedProvider as StorageProvider };

View File

@ -1,111 +0,0 @@
import { flatten } from 'lodash';
import React, { createContext, useState } from 'react';
import leftSections from '../data/leftSections';
const defaultState = {
selected: 'Onyx',
setSelected: () => {},
colors: {
textColor: '#212121',
primaryColor: '#f44336',
backgroundColor: '#FFFFFF',
},
blocks: [leftSections],
setBlocks: () => {},
setFixedBlocks: () => {},
setSupportedBlocks: () => {},
};
const TemplateContext = createContext(defaultState);
const TemplateProvider = ({ children }) => {
const [selected, setSelected] = useState(defaultState.selected);
const [colors, setColors] = useState(defaultState.colors);
const [blocks, setBlocks] = useState(defaultState.blocks);
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const move = (source, destination, droppableSource, droppableDestination) => {
const sourceClone = Array.from(source);
const destClone = Array.from(destination);
const [removed] = sourceClone.splice(droppableSource.index, 1);
destClone.splice(droppableDestination.index, 0, removed);
const result = {};
result[droppableSource.droppableId] = sourceClone;
result[droppableDestination.droppableId] = destClone;
return result;
};
const onDragEnd = (result) => {
const { source, destination } = result;
if (!destination) {
return;
}
const sInd = +source.droppableId;
const dInd = +destination.droppableId;
if (sInd === dInd) {
const items = reorder(blocks[sInd], source.index, destination.index);
const newState = [...blocks];
newState[sInd] = items;
setBlocks(newState);
} else {
const newResult = move(blocks[sInd], blocks[dInd], source, destination);
const newState = [...blocks];
newState[sInd] = newResult[sInd];
newState[dInd] = newResult[dInd];
setBlocks(newState);
}
};
const setFixedBlocks = (fixedBlocks) => {
const newBlocks = blocks.map((x) =>
x.filter((y) => !fixedBlocks.includes(y)),
);
setBlocks(newBlocks);
};
const setSupportedBlocks = (number) => {
if (number === blocks.length) return;
if (number > blocks.length) {
setBlocks([...blocks, []]);
}
if (number < blocks.length) {
setBlocks([flatten(blocks)]);
}
};
return (
<TemplateContext.Provider
value={{
colors,
blocks,
selected,
setColors,
setBlocks,
onDragEnd,
setSelected,
setFixedBlocks,
setSupportedBlocks,
}}
>
{children}
</TemplateContext.Provider>
);
};
export default TemplateContext;
export { TemplateProvider };

View File

@ -1,4 +1,4 @@
import React, { createContext, useEffect, useState } from 'react';
import React, { createContext, memo, useEffect, useState } from 'react';
const COLOR_CONFIG = {
light: {
@ -62,4 +62,6 @@ const ThemeProvider = ({ children }) => {
export default ThemeContext;
export { ThemeProvider };
const memoizedProvider = memo(ThemeProvider);
export { memoizedProvider as ThemeProvider };

View File

@ -1,6 +1,6 @@
import firebase from 'gatsby-plugin-firebase';
import { pick } from 'lodash';
import React, { createContext, useEffect, useState } from 'react';
import React, { createContext, memo, useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import useAuthState from '../hooks/useAuthState';
@ -77,4 +77,6 @@ const UserProvider = ({ children }) => {
export default UserContext;
export { UserProvider };
const memoizedProvider = memo(UserProvider);
export { memoizedProvider as UserProvider };