mirror of
https://github.com/BradNut/react-hooks-library
synced 2025-09-08 17:40:20 +00:00
Creating custom hook to set cookies, measure component size with ref, scroll freeze on component, get window width.
This commit is contained in:
parent
05fe1d93e7
commit
5cab62fd7e
13 changed files with 211 additions and 66 deletions
69
src/App.js
69
src/App.js
|
|
@ -5,6 +5,9 @@ import Toggle from './components/Toggle';
|
||||||
import Inc from './components/Inc';
|
import Inc from './components/Inc';
|
||||||
import Mount from './components/Mount';
|
import Mount from './components/Mount';
|
||||||
import Hover from './components/Hover';
|
import Hover from './components/Hover';
|
||||||
|
import Cookie from "./components/Cookie";
|
||||||
|
import { PageWrapper } from "./state";
|
||||||
|
import Nav from "./components/Nav";
|
||||||
import Menu from "./Menu";
|
import Menu from "./Menu";
|
||||||
import blue from "./blue.png";
|
import blue from "./blue.png";
|
||||||
import purp from "./purp.png";
|
import purp from "./purp.png";
|
||||||
|
|
@ -13,38 +16,42 @@ import green from "./green.png";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<PageWrapper>
|
||||||
<Header>
|
<div>
|
||||||
<Menu />
|
<Header>
|
||||||
<h1>Header</h1>
|
<Menu />
|
||||||
</Header>
|
<h1>Header</h1>
|
||||||
<Container>
|
</Header>
|
||||||
<h2>Super Cool</h2>
|
<Nav />
|
||||||
<Toggle />
|
<Container>
|
||||||
<Inc />
|
<h2>Super Cool</h2>
|
||||||
<Mount />
|
<Toggle />
|
||||||
<Hover />
|
<Inc />
|
||||||
|
<Mount />
|
||||||
|
<Cookie />
|
||||||
|
<Hover />
|
||||||
|
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
<Card style={{ background: "var(--purp)" }}>
|
<Card style={{ background: "var(--purp)" }}>
|
||||||
<h3>Some card</h3>
|
<h3>Some card</h3>
|
||||||
<img src={purp} />
|
<img src={purp} />
|
||||||
</Card>
|
</Card>
|
||||||
<Card style={{ background: "var(--blue)" }}>
|
<Card style={{ background: "var(--blue)" }}>
|
||||||
<h3>Some card</h3>
|
<h3>Some card</h3>
|
||||||
<img src={blue} />
|
<img src={blue} />
|
||||||
</Card>
|
</Card>
|
||||||
<Card style={{ background: "var(--black)" }}>
|
<Card style={{ background: "var(--black)" }}>
|
||||||
<h3>Some card</h3>
|
<h3>Some card</h3>
|
||||||
<img src={black} />
|
<img src={black} />
|
||||||
</Card>
|
</Card>
|
||||||
<Card style={{ background: "var(--green)" }}>
|
<Card style={{ background: "var(--green)" }}>
|
||||||
<h3>Some card</h3>
|
<h3>Some card</h3>
|
||||||
<img src={green} />
|
<img src={green} />
|
||||||
</Card>
|
</Card>
|
||||||
</CardGrid>
|
</CardGrid>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
39
src/Menu.js
39
src/Menu.js
|
|
@ -1,20 +1,25 @@
|
||||||
import React from "react";
|
import { useAppState } from "./state";
|
||||||
|
|
||||||
const Menu = () => (
|
const Menu = () => {
|
||||||
<svg viewBox="0 0 18 15" width="20">
|
const { toggleMenu } = useAppState();
|
||||||
<path
|
|
||||||
fill="#fff"
|
return (
|
||||||
d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"
|
<button onClick={toggleMenu}>
|
||||||
/>
|
<svg viewBox="0 0 18 15" width="20">
|
||||||
<path
|
<path
|
||||||
fill="#fff"
|
fill="#fff"
|
||||||
d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"
|
d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
fill="#fff"
|
fill="#fff"
|
||||||
d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"
|
d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
<path
|
||||||
);
|
fill="#fff"
|
||||||
|
d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)};
|
||||||
|
|
||||||
export default Menu;
|
export default Menu;
|
||||||
|
|
|
||||||
22
src/components/Cookie.js
Normal file
22
src/components/Cookie.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { useCookies } from "../hooks";
|
||||||
|
|
||||||
|
const Cookie = () => {
|
||||||
|
const [ cookie, setCookie ] = useCookies({ key: "tester" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{cookie || ''}</h1>
|
||||||
|
<input type="text" value={cookie} onChange={(e) => setCookie(e.target.value)} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cookie;
|
||||||
|
|
||||||
|
// Different types of api
|
||||||
|
// const { value, get, set } = useCookie({key, value})
|
||||||
|
// value
|
||||||
|
// const { value, get, set } = useCookie({key: anotherKey, value})
|
||||||
|
|
||||||
|
// const { get, set } = useCookie()
|
||||||
|
// get("theme")
|
||||||
|
|
@ -1,15 +1,23 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Card } from '../Elements';
|
import { Card } from '../Elements';
|
||||||
import black from "../black.png"
|
import black from "../black.png"
|
||||||
import { useHover } from '../hooks';
|
import { useHover, useWindowWidth, useMeasure } from '../hooks';
|
||||||
|
|
||||||
export const Hover = () => {
|
export const Hover = () => {
|
||||||
const [ isHovered, bind ] = useHover();
|
const [ isHovered, bind ] = useHover();
|
||||||
console.log('isHovered', isHovered);
|
const width = useWindowWidth();
|
||||||
|
const [{ref}, bounds] = useMeasure();
|
||||||
|
console.log('bounds', bounds);
|
||||||
|
|
||||||
|
if (width < 500) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card {...bind} style={{ background: isHovered ? "var(--purp)" : "var(--black)" }}>
|
<Card
|
||||||
|
ref={ref}
|
||||||
|
{...bind}
|
||||||
|
style={{ background: isHovered ? "var(--purp)" : "var(--black)" }}
|
||||||
|
>
|
||||||
<h3>Some card</h3>
|
<h3>Some card</h3>
|
||||||
<img src={black} />
|
<img src={black} />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
30
src/components/Nav.js
Normal file
30
src/components/Nav.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { useAppState } from "../state";
|
||||||
|
import { useScrollFreeze } from "../hooks";
|
||||||
|
|
||||||
|
const NavWrapper = () => {
|
||||||
|
const { isMenuOpen } = useAppState();
|
||||||
|
if (!isMenuOpen) return null;
|
||||||
|
return <Nav />
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Nav = () => {
|
||||||
|
const { toggleMenu } = useAppState();
|
||||||
|
useScrollFreeze ();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav style={{
|
||||||
|
background: 'var(--black)',
|
||||||
|
color: 'white',
|
||||||
|
position: 'fixed',
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
left: 0,
|
||||||
|
right: 0
|
||||||
|
}}>
|
||||||
|
<h1>Hello</h1>
|
||||||
|
<button onClick={toggleMenu}>Close</button>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NavWrapper;
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import React, { createConext, useState } from 'react';
|
|
||||||
import { useToggle } from '../hooks';
|
|
||||||
|
|
||||||
const AppContext = createConext({
|
|
||||||
isMenuOpen: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const PageWrapper = ({children}) => {
|
|
||||||
const {isToggled, toggle} = useToggle();
|
|
||||||
return <AppContext.Provider
|
|
||||||
value={{ isMenuOpen: false}}>
|
|
||||||
{children}
|
|
||||||
</AppContext.Provider>
|
|
||||||
};
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
|
export * from './useCookie';
|
||||||
export * from './useHover';
|
export * from './useHover';
|
||||||
export * from './useInc';
|
export * from './useInc';
|
||||||
|
export * from './useMeasure';
|
||||||
export * from './useMount';
|
export * from './useMount';
|
||||||
export * from './useToggle';
|
export * from './useScrollFreeze';
|
||||||
|
export * from './useToggle';
|
||||||
|
export * from './useWindowWidth';
|
||||||
|
|
|
||||||
13
src/hooks/useCookie.js
Normal file
13
src/hooks/useCookie.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
|
export const useCookies = ({ key }) => {
|
||||||
|
const initial = Cookies.get(key);
|
||||||
|
const [ cookie, setStateCookie ] = useState(initial);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Cookies.set(key, cookie)
|
||||||
|
}, [cookie, key]);
|
||||||
|
|
||||||
|
return [ cookie, setStateCookie ];
|
||||||
|
};
|
||||||
23
src/hooks/useMeasure.js
Normal file
23
src/hooks/useMeasure.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export const useMeasure = () => {
|
||||||
|
const ref = useRef();
|
||||||
|
|
||||||
|
const [bounds, setBounds] = useState({ left: 0, top: 0, width: 0, height: 0 });
|
||||||
|
|
||||||
|
const [ resizeO ] = useState(() => {
|
||||||
|
return new ResizeObserver(([entry]) => setBounds(entry.contentRect))
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
resizeO.observe(ref.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
return resizeO.disconnect();
|
||||||
|
};
|
||||||
|
}, [resizeO]);
|
||||||
|
|
||||||
|
return [{ ref }, bounds];
|
||||||
|
}
|
||||||
12
src/hooks/useScrollFreeze.js
Normal file
12
src/hooks/useScrollFreeze.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { useLayoutEffect } from 'react';
|
||||||
|
|
||||||
|
export const useScrollFreeze = () => {
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const original = window.getComputedStyle(document.body).overflow;
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.style.overflow = original;
|
||||||
|
};
|
||||||
|
}, [])
|
||||||
|
};
|
||||||
17
src/hooks/useWindowWidth.js
Normal file
17
src/hooks/useWindowWidth.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
export const useWindowWidth = () => {
|
||||||
|
const [width, setWidth] = useState(window.innerWidth);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setWidth(window.innerWidth);
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
17
src/state/PageWrapper.js
Normal file
17
src/state/PageWrapper.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
import { useToggle } from '../hooks';
|
||||||
|
|
||||||
|
export const AppContext = createContext({
|
||||||
|
isMenuOpen: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PageWrapper = ({children}) => {
|
||||||
|
const { isToggled, toggle } = useToggle(false);
|
||||||
|
return (
|
||||||
|
<AppContext.Provider value={{ isMenuOpen: isToggled, toggleMenu: toggle }}>
|
||||||
|
{children}
|
||||||
|
</AppContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAppState = () => useContext(AppContext);
|
||||||
1
src/state/index.js
Normal file
1
src/state/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './PageWrapper';
|
||||||
Loading…
Reference in a new issue