@1px.one/react-hooks 中文文档教程
React Hooks | 1px.one
一堆 React 钩子主要构建在 Web API 之上
Installation
yarn add @1px.one/react-hooks
或
npm i @1px.one/react-hooks
Description
< code>useNetworkStatus - 检测在线/离线网络状态的钩子。
usePageVisibility
- 建立在 Page Visibility API 之上的挂钩。 有助于检测活动标签。useResizeObserver
- 钩子构建在 Resize Observer API 之上。 它需要通过回调来检测指定元素的大小变化。useObservedSize
- 在useResizeObserver
挂钩之上构建挂钩。 另外返回指定元素的size
。 不需要回调。useFullscreen
- 建立在全屏 API 之上的挂钩。 用于以全屏模式显示指定的元素(及其后代)。useLocalStorage
- 设置和获取本地存储值的挂钩。useDisclosure
- 使用附加回调设置切换打开/关闭状态的钩子。useClipboard
- 将文本复制到剪贴板的挂钩。useElementHighlight
- 钩子用背景包裹指定的元素。useImagePreload
- 挂钩以使用加载和错误状态预加载图像。useIdleTimeout
- 在用户不活动 N 秒后挂钩调用函数。useWhyDidYouUpdate
- 在组件和其他挂钩中记录更新的道具和状态的挂钩。 有利于发展。
Network Status Hook
...
import { useNetworkStatus } from '@1px.one/react-hooks';
function SomeComponent() {
const online = useNetworkStatus();
useEffect(() => {
if (!online) {
// save form to localstorage
} else {
// restore form from localstorage
}
}, [online]);
return online ? <span>Connected</span> : <span>Connection lost</span>;
}
Page Visibility Hook
...
import { useNetworkStatus } from '@1px.one/react-hooks';
function SomeComponent() {
const online = useNetworkStatus();
useEffect(() => {
if (!online) {
// save form to localstorage
} else {
// restore form from localstorage
}
}, [online]);
return online ? <span>Connected</span> : <span>Connection lost</span>;
}
Resize Observer Hook
这个挂钩建立在 ResizeObserver API
...
import { useResizeObserver } from '@1px.one/react-hooks';
function SomeComponent() {
const [wrapperHeight, setHeight] = useState<number | undefined>();
const ref = useResizeObserver<HTMLDivElement>({
onResize: ({ height, width }) => setHeight(height),
});
const [blocks, addBlock] = useState([]);
const onAdd = () => {
addBlock([...blocks, (Math.random() * 100 + 50).toFixed(0) + 'px']);
};
const onDelete = (index) => {
addBlock(blocks.filter((_, i) => index !== i));
};
return (
<>
<p>Height: {wrapperHeight}</p>
<button onClick={onAdd}>Add +</button>
<div ref={ref}>
{blocks.map((block, index) => (
<div
style={{
height: block,
backgroundColor: index % 2 ? 'gray' : 'lightgray',
}}
>
Block height: {block}
<br />
<button onClick={() => onDelete(index)}>Delete</button>
</div>
))}
</div>
</>
);
}
Observed Size Hook
这个挂钩建立在 ResizeObserver API 并在内部使用 useResizeObserver
挂钩自动获取指定元素的 size
。 或者,您可以将 deboubceMs
参数作为 hook 的路径,如果需要,它会减慢更改 size
值的速度,但不会 对视觉元素大小变化的影响。 可能有助于防止昂贵的重新渲染。
...
import { useResizeObserver } from '@1px.one/react-hooks';
function SomeComponent() {
const [ref, size] = useObservedSize<HTMLDivElement>(100);
const [blocks, addBlock] = useState([]);
const onAdd = () => {
addBlock([...blocks, (Math.random() * 100 + 50).toFixed(0) + 'px']);
};
const onDelete = (index) => {
addBlock(blocks.filter((_, i) => index !== i));
};
return (
<>
<p>Height: {size.heigth}</p>
<button onClick={onAdd}>Add +</button>
<div ref={ref}>
{blocks.map((block, index) => (
<div
style={{
height: block,
backgroundColor: index % 2 ? 'gray' : 'lightgray',
}}
>
Block height: {block}
<br />
<button onClick={() => onDelete(index)}>Delete</button>
</div>
))}
</div>
</>
);
}
Fullscreen Hook
...
import { useFullScreen } from '@1px.one/react-hooks';
function SomeComponent() {
const playerElement = useRef<HTMLVideoElement>(null);
const { open, close, toggleFullScreen, isFullScreen } = useFullScreen({
element: playerElement,
});
return (
<>
<button onClick={toggleFullScreen}>Toggle fullscreen</button>
<video poster="video/preview.jpg" ref={playerElement}>
<source src="video/cats.ogv" type='video/ogg; codecs="theora, vorbis"' />
<source src="video/cats.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
<source src="video/cats.webm" type='video/webm; codecs="vp8, vorbis"' />
</video>
</>
);
}
Local Storage Hook
...
import { useLocalStorage } from '@1px.one/react-hooks';
function SomeComponent() {
const [value, setValue] = useLocalStorage('lastSubmit'); // store under the 'lastSubmit' key in LS
const onSubmit = () => {
const submitPayload = {
user: 'John Doe',
items: ['1', { foo: 'bar' }, 'baz'],
date: new Date().getUTCDate(),
};
setValue(submitPayload);
};
const status = value ? (
<span>
{value.user} submited at {value.date}
</span>
) : (
<span>Not submited yet!</span>
);
return (
<>
<button onClick={onSubmit}>Submit</button>
{status}
</>
);
}
Disclosure hook
...
import { useDisclosure } from '@1px.one/react-hooks';
function SomeComponent() {
const onOpenCb = () => {
console.log('content opened');
};
const onCloseCb = () => {
console.log('content closed');
};
const { isOpen, open, close } = useDisclosure(false, onOpenCb, onCloseCb);
const content = isOpen ? <span>Hello world!</span> : null;
return (
<>
<button onClick={isOpen ? close : open}>toggle content</button>
{content}
</>
);
}
Clipboard hook
...
import { useClipboard } from '@1px.one/react-hooks';
function SomeComponent() {
const onCopyCb = () => {
console.log('Copied');
};
// optional successResetIntervalMs parameter
// to set hasCopied to false in timeout
// defaults = 500 ms
const { copy, hasCopied } = useClipboard(onCopyCb, 1000);
const onCopyClick = () => {
copy('Hello world!'); // any text
};
useEffect(() => {
if (hasCopied) {
alert('Successfully copied!');
}
}, [hasCopied]);
return <button onClick={onCopyClick}>Copy text</button>;
}
Element Highlight Hook
可用于构建入职场景或学习交互式指南。 此挂钩呈现 Backdrop
以突出显示所选元素并提供回调 通过调用第二次从钩子返回的 setElement
来设置元素。
它允许为 Backdrop
设置额外的道具,但也支持所有默认的 HTMLDivElement
道具。
您可以通过设置
backdropColor
(默认值:rgba(0,0,0,0.75)
)、
zIndex 来配置
Backdrop
视图code>(默认值:999
)和
overlay
(默认值:false
)。
如果 overlay
设置为 true
,它将呈现覆盖
以阻止用户对所选元素的迭代。@TODO:平滑动画、调整大小、突出显示动态元素
...
import { useElementHighLight } from '@1px.one/react-hooks';
function SomeComponent() {
const [value, setValue] = useState('');
const inputRef = React.useRef();
const [currentElement, setElement, Backdrop] = useElementHighLight<
HTMLDivElement,
{ someExtraPropsToBackDrop: string }
>({ overlay: false, backdropColor: 'rgba(0,0,0,0.75)', zIndex: 999 });
React.useEffect(() => {
setElement(inputRef.current);
}, [inputRef]);
const onChange = (e) => {
setValue(e.target.value);
};
useEffect(() => {
if (value.length > 3) {
setElement(null);
}
}, [value]);
const onBackdropClick = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<>
<Backdrop onClick={onBackdropClick} someExtraPropsToBackDrop={'foo'} />
<input value={value} onChange={onChange} ref={inputRef} />
</>
);
}
Image preload Hook
...
import { useImagePreload } from '@1px.one/react-hooks';
const imgSrc = 'https://example.com/static/dog.jpg';
const imgPlaceholder = 'https://example.com/static/placeholder.jpg'; // optionally
export const SomeComponent = () => {
const { source, loading, error } = useImagePreload(imgSrc, imgPlaceholder);
if (loading) {
return <span>Image loading...</span>;
} else if (error) {
return <span>Error occured</span>;
} else {
return <img src={source} alt="dog" />;
}
}
Idle Timeout Hook
此组件将在用户不活动 5 秒后触发 onClose
回调。 它监听load
、mousemove
、mousedown
、click
、scroll
、按键
, touchcancel
, touchend
、touchmove
、touchstart
事件。
...
import { useIdleTimeOut } from '@1px.one/react-hooks';
export const SomeComponent = ({ onClose, isOpen }) => {
useIdleTimeOut(5000, onClose);
if (isOpen) {
return <p>This is autoclosing notification</p>;
}
return null;
}
Debug Hook
这个钩子将在控制台中显示每个渲染器上的道具之间的差异。 它有助于调试复杂的组件。 这个钩子支持嵌套对象比较。 仅在开发模式下使用它。
...
import { useWhyDidYouUpdate } from '@1px.one/react-hooks';
function SomeComponent(props) {
useWhyDidYouUpdate(props, 'my complicated component to debug');
// also you can specify console prefix to identify current hook usage
// For example if props.name changed it will log:
// [why-did-you-update] my complicated component to debug {name: { from: 'Jim', to: 'Joe' }}
return <>...</>;
}
TODO
- Add SSR support
- Add demo
- Tests
- Add useAccelerometer
- Add useParallax
React Hooks | 1px.one
Bunch of React hooks mostly built on top of Web APIs
Installation
yarn add @1px.one/react-hooks
or
npm i @1px.one/react-hooks
Description
useNetworkStatus
- Hook to detect online/offline network status.usePageVisibility
- Hook built on top of Page Visibility API. Helps to detect active tab.useResizeObserver
- Hook build on top Resize Observer API. It requires to pass callback to detect size changes of specified Element.useObservedSize
- Hook build on topuseResizeObserver
hook. Additionally returnssize
of specified Element. No callback needed.useFullscreen
- Hook built on top of Fullscreen API. Used to present specified Element (and its descendants) in full-screen mode.useLocalStorage
- Hook to set and get localstorage values.useDisclosure
- Hook to set toggle opened/closed state with additional callbacks.useClipboard
- Hook to copy text to clipboard.useElementHighlight
- Hook to wrap specified Element with backdrop.useImagePreload
- Hook to preload image with loading and error states.useIdleTimeout
- Hook to call function after N-seconds of user inactivity.useWhyDidYouUpdate
- Hook to log updated props and state inside components and other hooks. Helpful for development.
Network Status Hook
...
import { useNetworkStatus } from '@1px.one/react-hooks';
function SomeComponent() {
const online = useNetworkStatus();
useEffect(() => {
if (!online) {
// save form to localstorage
} else {
// restore form from localstorage
}
}, [online]);
return online ? <span>Connected</span> : <span>Connection lost</span>;
}
Page Visibility Hook
...
import { useNetworkStatus } from '@1px.one/react-hooks';
function SomeComponent() {
const online = useNetworkStatus();
useEffect(() => {
if (!online) {
// save form to localstorage
} else {
// restore form from localstorage
}
}, [online]);
return online ? <span>Connected</span> : <span>Connection lost</span>;
}
Resize Observer Hook
This hook built on top of ResizeObserver API
...
import { useResizeObserver } from '@1px.one/react-hooks';
function SomeComponent() {
const [wrapperHeight, setHeight] = useState<number | undefined>();
const ref = useResizeObserver<HTMLDivElement>({
onResize: ({ height, width }) => setHeight(height),
});
const [blocks, addBlock] = useState([]);
const onAdd = () => {
addBlock([...blocks, (Math.random() * 100 + 50).toFixed(0) + 'px']);
};
const onDelete = (index) => {
addBlock(blocks.filter((_, i) => index !== i));
};
return (
<>
<p>Height: {wrapperHeight}</p>
<button onClick={onAdd}>Add +</button>
<div ref={ref}>
{blocks.map((block, index) => (
<div
style={{
height: block,
backgroundColor: index % 2 ? 'gray' : 'lightgray',
}}
>
Block height: {block}
<br />
<button onClick={() => onDelete(index)}>Delete</button>
</div>
))}
</div>
</>
);
}
Observed Size Hook
This hook built on top of ResizeObserver API and uses useResizeObserver
hook inside to automate getting size
of specified element. Optionally, you can path deboubceMs
argument to hook, it will slowdown changing size
value if needed, but not effects on visual element size changing. Could be useful to prevent expensive re-rendering.
...
import { useResizeObserver } from '@1px.one/react-hooks';
function SomeComponent() {
const [ref, size] = useObservedSize<HTMLDivElement>(100);
const [blocks, addBlock] = useState([]);
const onAdd = () => {
addBlock([...blocks, (Math.random() * 100 + 50).toFixed(0) + 'px']);
};
const onDelete = (index) => {
addBlock(blocks.filter((_, i) => index !== i));
};
return (
<>
<p>Height: {size.heigth}</p>
<button onClick={onAdd}>Add +</button>
<div ref={ref}>
{blocks.map((block, index) => (
<div
style={{
height: block,
backgroundColor: index % 2 ? 'gray' : 'lightgray',
}}
>
Block height: {block}
<br />
<button onClick={() => onDelete(index)}>Delete</button>
</div>
))}
</div>
</>
);
}
Fullscreen Hook
...
import { useFullScreen } from '@1px.one/react-hooks';
function SomeComponent() {
const playerElement = useRef<HTMLVideoElement>(null);
const { open, close, toggleFullScreen, isFullScreen } = useFullScreen({
element: playerElement,
});
return (
<>
<button onClick={toggleFullScreen}>Toggle fullscreen</button>
<video poster="video/preview.jpg" ref={playerElement}>
<source src="video/cats.ogv" type='video/ogg; codecs="theora, vorbis"' />
<source src="video/cats.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
<source src="video/cats.webm" type='video/webm; codecs="vp8, vorbis"' />
</video>
</>
);
}
Local Storage Hook
...
import { useLocalStorage } from '@1px.one/react-hooks';
function SomeComponent() {
const [value, setValue] = useLocalStorage('lastSubmit'); // store under the 'lastSubmit' key in LS
const onSubmit = () => {
const submitPayload = {
user: 'John Doe',
items: ['1', { foo: 'bar' }, 'baz'],
date: new Date().getUTCDate(),
};
setValue(submitPayload);
};
const status = value ? (
<span>
{value.user} submited at {value.date}
</span>
) : (
<span>Not submited yet!</span>
);
return (
<>
<button onClick={onSubmit}>Submit</button>
{status}
</>
);
}
Disclosure hook
...
import { useDisclosure } from '@1px.one/react-hooks';
function SomeComponent() {
const onOpenCb = () => {
console.log('content opened');
};
const onCloseCb = () => {
console.log('content closed');
};
const { isOpen, open, close } = useDisclosure(false, onOpenCb, onCloseCb);
const content = isOpen ? <span>Hello world!</span> : null;
return (
<>
<button onClick={isOpen ? close : open}>toggle content</button>
{content}
</>
);
}
Clipboard hook
...
import { useClipboard } from '@1px.one/react-hooks';
function SomeComponent() {
const onCopyCb = () => {
console.log('Copied');
};
// optional successResetIntervalMs parameter
// to set hasCopied to false in timeout
// defaults = 500 ms
const { copy, hasCopied } = useClipboard(onCopyCb, 1000);
const onCopyClick = () => {
copy('Hello world!'); // any text
};
useEffect(() => {
if (hasCopied) {
alert('Successfully copied!');
}
}, [hasCopied]);
return <button onClick={onCopyClick}>Copy text</button>;
}
Element Highlight Hook
Could be used to build onboarding scenario or learning interactive guide. This hook renders Backdrop
to highlight selected element and provides callbacks to set elements by calling setElement
returned second from hook.
It allows to set additional props to Backdrop
but also supports all default HTMLDivElement
props.
You can configure Backdrop
view by setting
backdropColor
(defaults: rgba(0,0,0,0.75)
),
zIndex
(defaults: 999
) and
overlay
(defaults: false
).
If overlay
set to true
it will render overlaying <div />
to block user iteration with selected element.
@TODO: Smooth animation, resizing, highlighting dynamic elements
...
import { useElementHighLight } from '@1px.one/react-hooks';
function SomeComponent() {
const [value, setValue] = useState('');
const inputRef = React.useRef();
const [currentElement, setElement, Backdrop] = useElementHighLight<
HTMLDivElement,
{ someExtraPropsToBackDrop: string }
>({ overlay: false, backdropColor: 'rgba(0,0,0,0.75)', zIndex: 999 });
React.useEffect(() => {
setElement(inputRef.current);
}, [inputRef]);
const onChange = (e) => {
setValue(e.target.value);
};
useEffect(() => {
if (value.length > 3) {
setElement(null);
}
}, [value]);
const onBackdropClick = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<>
<Backdrop onClick={onBackdropClick} someExtraPropsToBackDrop={'foo'} />
<input value={value} onChange={onChange} ref={inputRef} />
</>
);
}
Image preload Hook
...
import { useImagePreload } from '@1px.one/react-hooks';
const imgSrc = 'https://example.com/static/dog.jpg';
const imgPlaceholder = 'https://example.com/static/placeholder.jpg'; // optionally
export const SomeComponent = () => {
const { source, loading, error } = useImagePreload(imgSrc, imgPlaceholder);
if (loading) {
return <span>Image loading...</span>;
} else if (error) {
return <span>Error occured</span>;
} else {
return <img src={source} alt="dog" />;
}
}
Idle Timeout Hook
This component will fire onClose
callback after 5 seconds of user inactivity. It listens to load
, mousemove
, mousedown
, click
, scroll
, keypress
, touchcancel
, touchend
, touchmove
, touchstart
events.
...
import { useIdleTimeOut } from '@1px.one/react-hooks';
export const SomeComponent = ({ onClose, isOpen }) => {
useIdleTimeOut(5000, onClose);
if (isOpen) {
return <p>This is autoclosing notification</p>;
}
return null;
}
Debug Hook
This hook will show in console difference between props on each render. It helps to debug complicated components. This hook supports nested objects compare. Use it only in development mode.
...
import { useWhyDidYouUpdate } from '@1px.one/react-hooks';
function SomeComponent(props) {
useWhyDidYouUpdate(props, 'my complicated component to debug');
// also you can specify console prefix to identify current hook usage
// For example if props.name changed it will log:
// [why-did-you-update] my complicated component to debug {name: { from: 'Jim', to: 'Joe' }}
return <>...</>;
}
TODO
- Add SSR support
- Add demo
- Tests
- Add useAccelerometer
- Add useParallax