Skip to content

Instantly share code, notes, and snippets.

@tolotrasmile
Last active July 24, 2019 07:55
Show Gist options
  • Save tolotrasmile/bd3bd4b65e001cdcada1f4c3b48aba6a to your computer and use it in GitHub Desktop.
Save tolotrasmile/bd3bd4b65e001cdcada1f4c3b48aba6a to your computer and use it in GitHub Desktop.
// hooks.js
import { useCallback, useEffect, useReducer, useRef } from "react";
export function useRefMounted() {
// To prevent state update when component is unmounted
const isMounted = useRef(true);
useEffect(() => {
return () => {
// called when the component is going to unmount
isMounted.current = false;
};
}, []);
return isMounted;
}
export function useStates(initialValues) {
const [state, dispatch] = useReducer(
// Merge old and new state
(oldState, newState) => ({ ...oldState, ...newState }),
initialValues
);
// To prevent state update when component is unmounted
const isMounted = useRefMounted();
const setState = useCallback(
value => {
if (isMounted.current) {
dispatch(value);
}
},
[dispatch, isMounted]
);
return [state, setState];
}
// From react-use
const usePromise = () => {
const refMounted = useRefMounted();
return useCallback(
promise =>
new Promise((resolve, reject) => {
const onValue = value => {
if (refMounted.current) {
resolve(value);
}
};
const onError = error => {
if (refMounted.current) {
reject(error);
}
};
promise.then(onValue, onError);
}),
[refMounted]
);
};
export function useFetch(url, { format = "json", options = {} }) {
const [state, setState] = useStates({
data: null,
status: "idle",
error: null
});
const makePromise = usePromise();
const makeRequest = useCallback(async () => {
setState({ status: "loading" });
try {
const data = await makePromise(
fetch(url, options).then(x => x[format]())
);
setTimeout(() => {
setState({ data, status: "success", error: null });
}, 2000);
} catch (error) {
setState({ status: "failure", error });
}
}, [format, makePromise, options, setState, url]);
return [state, makeRequest];
}
export function useYellowBox() {
useEffect(() => {
console.disableYellowBox = true;
return () => {
console.disableYellowBox = false;
};
}, []);
}
// --------------------------------------------
// Loader.js
import React, { createContext, useContext, useMemo, useState } from "react";
const LoaderContext = createContext();
function useLoader() {
const context = useContext(LoaderContext);
if (!context) {
throw new Error(`useLoader must be used within a LoaderContext`);
}
return context;
}
function LoaderProvider({
children,
component: Component = Loader,
initialValue = false,
...props
}) {
const [loading, setLoading] = useState(() => initialValue);
const value = useMemo(() => setLoading, []);
return (
<LoaderContext.Provider value={value} {...props}>
<Component loading={loading} />
{children}
</LoaderContext.Provider>
);
}
export { LoaderProvider, useLoader };
function Loader({ loading }) {
return loading ? (
<div
style={{
position: "absolute",
top: 0,
right: 0,
height: "100vh",
width: "100vw",
zIndex: 9999,
backgroundColor: "black",
opacity: 0.5,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
Loading
</div>
) : null;
}
Loader.defaultProps = {
loading: false
};
export default Loader;
// --------------------------------------------
// App.js
import React, { useEffect } from "react";
import { useFetch } from "./hooks";
import { useLoader } from "./Loader";
function App() {
const url = "https://jsonplaceholder.typicode.com/todos";
const [data, dispatch] = useFetch(url);
const setLoading = useLoader();
useEffect(() => {
console.log("run effect");
if (data) {
setLoading(data.status === "loading");
}
}, [data, setLoading]);
return (
<div>
<button onClick={dispatch}>Fetch</button>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default App;
// --------------------------------------------
// index.js
import App from "./App";
import { LoaderProvider } from "./Loader";
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(
<LoaderProvider>
<App />
</LoaderProvider>,
document.getElementById("root")
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment