├── .gitignore ├── tsconfig.json ├── package.json ├── README.md ├── src ├── index.tsx └── ReactFastPrefetch.tsx ├── index.js.map ├── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "es2015", 5 | "removeComments": true, 6 | "sourceMap": true, 7 | "jsx": "react", 8 | "lib": ["es5", "es2015", "dom", "scripthost"], 9 | "moduleResolution": "node", 10 | "outDir": "./" 11 | }, 12 | "files": ["src/index.tsx"], 13 | "esModuleInterop": true 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-fast-prefetch", 3 | "version": "4.0.0", 4 | "description": "Begin fetching data before your react component renders", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm test", 8 | "build": "tsc --jsx react" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/leedauphinee/react-fast-prefetch.git" 13 | }, 14 | "author": "https://github.com/leedauphinee", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/leedauphinee/react-prefetch/issues" 18 | }, 19 | "homepage": "https://github.com/leedauphinee/react-prefetch#readme", 20 | "dependencies": { 21 | "axios": "0.19.2" 22 | }, 23 | "devDependencies": { 24 | "@types/react": "^16.9.35", 25 | "@types/react-dom": "^16.9.8", 26 | "typescript": "^3.9.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-fast-prefetch 2 | 3 | Start prefetching data in your react apps before your components renders. 4 | 5 | ``` 6 | yarn add react-fast-prefetch 7 | ``` 8 | 9 | Example using redux: https://codesandbox.io/s/react-fast-prefetch-redux-f8f7n 10 | 11 | Example VS not using it: https://codesandbox.io/s/smart-fetch-skz09 12 | 13 | ## How to use it 14 | 15 | Export the ReactPrefetchProvider and wrap your app in it. This allows us to use the useReactPrefetch from anywhere on our site. 16 | 17 | ```javascript 18 | import { ReactPrefetchProvider } from "react-fast-prefetch"; 19 | 20 | 21 | 22 | ; 23 | ``` 24 | 25 | Import the useReactPrefetch hook into a component where your href link is located. 26 | Destructure the prefetch function from the hook, and call it onMouseEnter or onMouseDown depending on the priorty of your link. Applying to many onMouseEnter prefetches could cause memory issues, so it's recommended to only use onMouseEnter on very high traffic links. 27 | 28 | ```javascript 29 | import { useReactPrefetch } from "react-fast-prefetch"; 30 | 31 | const Home = () => { 32 | const { prefetch } = useReactPrefetch(); 33 | 34 | const prefetchData = () => { 35 | prefetch("https://jsonplaceholder.typicode.com/todos/1"); 36 | }; 37 | 38 | return ; 39 | }; 40 | ``` 41 | 42 | In your component that that needs data, destructure fetchData from the hook, and use it like you would with axios. 43 | 44 | ```javascript 45 | import { useReactPrefetch } from "react-fast-prefetch" 46 | 47 | const About = () => { 48 | const { fetchData } = useReactPrefetch() 49 | 50 | useEffect(() => { 51 | fetchData('https://jsonplaceholder.typicode.com/todos/1').then(response => 52 | // USE THE RESPONSE FROM FETCH HERE 53 | ); 54 | }, []) 55 | 56 | return ( 57 | 58 | ) 59 | 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import axios from "axios"; 3 | 4 | const ReactPrefetchContext = React.createContext([]); 5 | 6 | export const ReactPrefetchProvider = ({ children }) => { 7 | const PromiseRef = React.useRef([]); 8 | 9 | const prefetch = (url: string, options = {}) => { 10 | const newData = PromiseRef.current.find((data) => data.url === url); 11 | 12 | if (newData) { 13 | return; 14 | } 15 | 16 | const promise = axios.get(url, options); 17 | 18 | const data = [...PromiseRef.current, { url, value: promise }]; 19 | PromiseRef.current = data; 20 | }; 21 | 22 | const fetchData = (url, options = {}) => { 23 | const test1 = PromiseRef.current.find((data) => data.url === url); 24 | 25 | if (test1) { 26 | if (test1.value instanceof Promise) { 27 | return test1.value; 28 | } 29 | } 30 | return new Promise((resolve, reject) => { 31 | const newData = PromiseRef.current.find((data) => data.url === url); 32 | if (newData) { 33 | resolve(newData.value); 34 | 35 | const data = PromiseRef.current.filter((d) => d.url !== url); 36 | 37 | PromiseRef.current = data; 38 | } else { 39 | axios 40 | .get(url, options) 41 | .then((res) => { 42 | resolve(res); 43 | }) 44 | .catch((err) => { 45 | reject(err); 46 | }); 47 | } 48 | }); 49 | }; 50 | 51 | const data = [PromiseRef.current, prefetch, fetchData]; 52 | 53 | return ( 54 | 55 | {children} 56 | 57 | ); 58 | }; 59 | 60 | export const useReactPrefetch = () => { 61 | const context = React.useContext(ReactPrefetchContext); 62 | if (context === undefined) { 63 | throw new Error( 64 | "useReactPrefetch can only be used inside ReactPrefetchProvider" 65 | ); 66 | } 67 | const [PromiseRef, prefetch, fetchData] = context; 68 | 69 | React.useEffect(() => { 70 | return () => { 71 | return (PromiseRef.current = []); 72 | }; 73 | }, []); 74 | 75 | return { prefetch, fetchData }; 76 | }; 77 | -------------------------------------------------------------------------------- /src/ReactFastPrefetch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import axios from "axios"; 3 | 4 | const ReactPrefetchContext = React.createContext([]); 5 | 6 | export const ReactPrefetchProvider = ({ children }) => { 7 | const PromiseRef = React.useRef([]); 8 | 9 | const prefetch = (url: string, options = {}) => { 10 | const newData = PromiseRef.current.find((data) => data.url === url); 11 | 12 | if (newData) { 13 | return; 14 | } 15 | 16 | const promise = axios.get(url, options); 17 | 18 | const data = [...PromiseRef.current, { url, value: promise }]; 19 | PromiseRef.current = data; 20 | }; 21 | 22 | const fetchData = (url, options = {}) => { 23 | const test1 = PromiseRef.current.find((data) => data.url === url); 24 | 25 | if (test1) { 26 | if (test1.value instanceof Promise) { 27 | return test1.value; 28 | } 29 | } 30 | return new Promise((resolve, reject) => { 31 | const newData = PromiseRef.current.find((data) => data.url === url); 32 | if (newData) { 33 | resolve(newData.value); 34 | 35 | const data = PromiseRef.current.filter((d) => d.url !== url); 36 | 37 | PromiseRef.current = data; 38 | } else { 39 | axios 40 | .get(url, options) 41 | .then((res) => { 42 | resolve(res); 43 | }) 44 | .catch((err) => { 45 | reject(err); 46 | }); 47 | } 48 | }); 49 | }; 50 | 51 | const data = [PromiseRef.current, prefetch, fetchData]; 52 | 53 | return ( 54 | 55 | {children} 56 | 57 | ); 58 | }; 59 | 60 | export const useReactPrefetch = () => { 61 | const ReactPrefetchContext = React.createContext([]); 62 | const context = React.useContext(ReactPrefetchContext); 63 | if (context === undefined) { 64 | throw new Error( 65 | "useReactPrefetch can only be used inside ReactPrefetchProvider" 66 | ); 67 | } 68 | const [PromiseRef, prefetch, fetchData] = context; 69 | 70 | React.useEffect(() => { 71 | return () => { 72 | return (PromiseRef.current = []); 73 | }; 74 | }, []); 75 | 76 | return { prefetch, fetchData }; 77 | }; 78 | -------------------------------------------------------------------------------- /index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.tsx"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import axios from "axios"; 3 | const ReactPrefetchContext = React.createContext([]); 4 | export const ReactPrefetchProvider = ({ children }) => { 5 | const PromiseRef = React.useRef([]); 6 | const prefetch = (url, options = {}) => { 7 | const newData = PromiseRef.current.find((data) => data.url === url); 8 | if (newData) { 9 | return; 10 | } 11 | const promise = axios.get(url, options); 12 | const data = [...PromiseRef.current, { url, value: promise }]; 13 | PromiseRef.current = data; 14 | }; 15 | const fetchData = (url, options = {}) => { 16 | const test1 = PromiseRef.current.find((data) => data.url === url); 17 | if (test1) { 18 | if (test1.value instanceof Promise) { 19 | return test1.value; 20 | } 21 | } 22 | return new Promise((resolve, reject) => { 23 | const newData = PromiseRef.current.find((data) => data.url === url); 24 | if (newData) { 25 | resolve(newData.value); 26 | const data = PromiseRef.current.filter((d) => d.url !== url); 27 | PromiseRef.current = data; 28 | } 29 | else { 30 | axios 31 | .get(url, options) 32 | .then((res) => { 33 | resolve(res); 34 | }) 35 | .catch((err) => { 36 | reject(err); 37 | }); 38 | } 39 | }); 40 | }; 41 | const data = [PromiseRef.current, prefetch, fetchData]; 42 | return (React.createElement(ReactPrefetchContext.Provider, { value: data }, children)); 43 | }; 44 | export const useReactPrefetch = () => { 45 | const context = React.useContext(ReactPrefetchContext); 46 | if (context === undefined) { 47 | throw new Error("useReactPrefetch can only be used inside ReactPrefetchProvider"); 48 | } 49 | const [PromiseRef, prefetch, fetchData] = context; 50 | React.useEffect(() => { 51 | return () => { 52 | return (PromiseRef.current = []); 53 | }; 54 | }, []); 55 | return { prefetch, fetchData }; 56 | }; 57 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/prop-types@*": 6 | version "15.7.3" 7 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" 8 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== 9 | 10 | "@types/react-dom@^16.9.8": 11 | version "16.9.8" 12 | resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" 13 | integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== 14 | dependencies: 15 | "@types/react" "*" 16 | 17 | "@types/react@*", "@types/react@^16.9.35": 18 | version "16.9.35" 19 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368" 20 | integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ== 21 | dependencies: 22 | "@types/prop-types" "*" 23 | csstype "^2.2.0" 24 | 25 | axios@0.19.2: 26 | version "0.19.2" 27 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" 28 | integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== 29 | dependencies: 30 | follow-redirects "1.5.10" 31 | 32 | csstype@^2.2.0: 33 | version "2.6.10" 34 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" 35 | integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== 36 | 37 | debug@=3.1.0: 38 | version "3.1.0" 39 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 40 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 41 | dependencies: 42 | ms "2.0.0" 43 | 44 | follow-redirects@1.5.10: 45 | version "1.5.10" 46 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" 47 | integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== 48 | dependencies: 49 | debug "=3.1.0" 50 | 51 | ms@2.0.0: 52 | version "2.0.0" 53 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 54 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 55 | 56 | typescript@^3.9.3: 57 | version "3.9.3" 58 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" 59 | integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== 60 | --------------------------------------------------------------------------------