@1px.one/react-hooks 中文文档教程

发布于 4年前 浏览 25 项目主页 更新于 3年前

React Hooks | 1px.one

一堆 React 钩子主要构建在 Web API 之上

npm version

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 回调。 它监听loadmousemovemousedownclickscroll按键, touchcancel, touchendtouchmovetouchstart 事件。

...

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

npm version

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 top useResizeObserver hook. Additionally returns size 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
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文