React 提供了自定义 Hooks 的特性,我们可以根据这个特性创建出很多有意思的功能,今天就来分享一些个人认为还不错的 Hooks,共计 15 个。
如果对于 React Hooks 还不是特别熟悉的话,可以先参阅这篇文章:React Hooks 温故而知新
useClippy
官方文档:https://github.com/CharlesStover/use-clippy
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import useClippy from 'use-clippy'; export default () => { const [clipboard, setClipboard] = useClippy(); return ( <div> <button onClick={() => { alert(`粘贴板内容为: ${clipboard}`); }} > 读取粘贴板 </button> <button onClick={() => { setClipboard(`新内容: ${Math.random()}`); }} > 写入粘贴板 </button> </div> ); }; |
useWindowSize
官方文档:https://github.com/jaredLunde/react-hook/tree/master/packages/window-size
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 | import { useWindowSize } from '@react-hook/window-size'; // import { useWindowSize } from '@react-hook/window-size/throttled'; export default (props) => { const [width, height] = useWindowSize(); return ( <div> width: {width}, height: {height} </div> ); }; |
useMediaQuery
官方文档:https://github.com/jaredLunde/react-hook/tree/master/packages/media-query
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import React from 'react'; import { useMediaQuery, useMediaQueries } from '@react-hook/media-query'; // Using a single media query // export default () => { // const matches = useMediaQuery('only screen and (min-width: 400px)'); // return `Matches? ${matches ? 'Matched!' : 'Nope'}`; // }; // Using multiple media queries export default () => { const { matches, matchesAny, matchesAll } = useMediaQueries({ screen: 'screen', width: '(min-width: 400px)', }); return ( <ul> <li>Screen matched? {matches.screen ? 'Yes' : 'No'}</li> <li>Width matched? {matches.width ? 'Yes' : 'No'}</li> <li>All matched? {matchesAll ? 'Yes' : 'No'}</li> <li>Any matched? {matchesAny ? 'Yes' : 'No'}</li> </ul> ); }; |
useAsync
官方文档:https://github.com/jaredLunde/react-hook/tree/master/packages/async
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import { useAsync } from '@react-hook/async'; export default () => { const [{ status, cancel, error, value }, call] = useAsync(() => { return new Promise((resolve) => setTimeout(() => resolve('Loaded'), 3000)); }); switch (status) { case 'loading': return ( <div> <button onClick={cancel}>Cancel</button> Loading... </div> ); case 'cancelled': return ( <div> Cancelled. <button onClick={call}>Try again</button> </div> ); case 'error': return `Error: ${error}`; case 'success': return value || 'Success!'; default: return <button onClick={call}>Load me</button>; } }; |
useBrowserContextCommunication
官方文档:https://github.com/AvraamMavridis/react-window-communication-hook
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import useBrowserContextCommunication from 'react-window-communication-hook'; export default () => { // communicationState 是一个 {lastMessage, messages} 对象,用于从其它的浏览器上下文接收数据 const [communicationState, postMessage] = useBrowserContextCommunication( 'channel' ); const [status, setStatus] = useState('login'); function logout() { setStatus('logout'); postMessage('logout'); } const isLogout = [communicationState.lastMessage, status].includes('logout'); return ( <div> <h1>状态:{isLogout ? '已退出' : '已登录'}</h1> <button onClick={logout}>退出</button> </div> ); }; |
可以在浏览器里打开两个 Tab,然后在其中一个页面点击「退出」按钮,会发现两个 Tab 的页面都发生了变化。
useScript
官方文档:https://github.com/hupe1980/react-script-hook
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { StripeProvider } from 'react-stripe-elements'; import useScript from 'react-script-hook'; export default () => { const [loading, error] = useScript({ src: 'https://js.stripe.com/v3/' }); if (loading) return <h3>Loading Stripe API...</h3>; if (error) return <h3>Failed to load Stripe API: {error.message}</h3>; return ( <StripeProvider apiKey="pk_test_6pRNASCoBOKtIshFeQd4XMUh"> <div>Hello</div> </StripeProvider> ); }; |
当然也可以以回调函数的形式使用:
1 2 3 4 | useScript({ src: 'https://js.stripe.com/v3/', onload: () => console.log('Script loaded!') }) |
useLocalStorage
官方文档:https://github.com/rehooks/local-storage
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { useLocalStorage, writeStorage } from '@rehooks/local-storage'; let counter = 0; export default () => { const [counterData] = useLocalStorage('counter'); return ( <> {counter} <button onClick={() => writeStorage('counter', ++counter)}>Write</button> <button onClick={() => alert(counterData)}>Read</button> </> ); }; |
useIdb
官方文档:https://github.com/kigiri/react-use-idb
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { useIdb } from 'react-use-idb'; export default () => { const [value, setValue] = useIdb('my-key', 'foo'); return ( <div> <div>Value: {value}</div> <button onClick={() => setValue('bar')}>bar</button> <button onClick={() => setValue('baz')}>baz</button> </div> ); }; |
use-mouse-action
官方文档:https://github.com/dimitrinicolas/use-mouse-action
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import useMouseAction from 'use-mouse-action'; export default () => { const props = useMouseAction({ onAction: () => console.log('You clicked or mouse downed me!'), down: true, }); return ( <button type="button" {...props}> Click me fast! </button> ); }; |
useDebounce
官方文档:https://github.com/jaredLunde/react-hook/tree/master/packages/debounce
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 | import {useDebounce, useDebounceCallback} from '@react-hook/debounce' const Component = (props) => { // at a basic level, used just like useState const [value, setValue] = useDebounce('initialValue') } const useMyCallback = (initialState, wait, leading) => { // this is the same code useDebounce() uses to debounce setState const [state, setState] = useState(initialState) return [state, useDebounceCallback(setState, wait, leading)] } |
useThrottle
官方文档:https://github.com/jaredLunde/react-hook/tree/master/packages/throttle
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 | import {useThrottle, useThrottleCallback} from '@react-hook/throttle' const Component = (props) => { // at a basic level, used just like useState const [value, setValue] = useThrottle('initialValue') } const useMyCallback = (initialState, fps, leading) => { // this is the same code useThrottle() uses to throttle setState const [state, setState] = useState(initialState) return [state, useThrottleCallback(setState, fps, leading)] } |
useOnlineStatus
官方文档:https://github.com/rehooks/online-status
代码示例:
1 2 3 4 5 6 7 8 9 10 | import useOnlineStatus from '@rehooks/online-status'; export default () => { const onlineStatus = useOnlineStatus(); return ( <div> <h1>You are {onlineStatus ? 'Online' : 'Offline'}</h1> </div> ); }; |
useDocumentTitle
官方文档:https://github.com/rehooks/document-title
代码示例:
1 2 3 4 5 6 | import useDocumentTitle from '@rehooks/document-title'; export default () => { useDocumentTitle('Page Title'); return <div />; }; |
useNetworkStatus
官方文档:https://github.com/rehooks/network-status/
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | import useNetworkStatus from '@rehooks/network-status'; export default () => { let connection = useNetworkStatus(); return ( <div> <div>downlink: {connection.downlink}</div> <div>effectiveType: {connection.effectiveType}</div> <div>rtt: {connection.rtt}</div> <div>saveData: {connection.saveData ? 'yes' : 'no'}</div> </div> ); }; |
useSpeechSynthesis
官方文档:https://www.npmjs.com/package/react-speech-kit
在线示例:https://mikeyparton.github.io/react-speech-kit/
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import { useSpeechSynthesis, useSpeechRecognition } from 'react-speech-kit'; export default () => { const [value, setValue] = useState(''); const { speak } = useSpeechSynthesis(); const { listen, listening, stop } = useSpeechRecognition({ onResult: (result) => { setValue(result); }, }); return ( <div> <textarea value={value} onChange={(event) => setValue(event.target.value)} /> <br /> <button onMouseDown={listen} onMouseUp={stop}> Listen </button> <button onClick={() => speak({ text: value })}>Speak</button> {listening && <div>Go ahead I'm listening</div>} </div> ); }; |
可以按住