跟着 ahooks 写 Hook 之 useNetwork 、useToggle

336 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情

💻文档地址:ahooks.js.org/zh-CN/

👨‍💻github地址:github.com/alibaba/hoo…


useNetwork

🧪 这是一个实验中的功能,在不同浏览器中适合使用的前缀。

function getConnection() {
  const nav = navigator as any;
  if (!isObject(nav)) return null;
  return nav.connection || nav.mozConnection || nav.webkitConnection;
}

图片.png

NetworkInformation 提供有关设备正在使用的连接与网络进行通信的信息。

属性描述类型
online网络是否为在线boolean
sinceonline 最后改变时间Date
rtt当前连接下评估的往返时延number
type设备使用与所述网络进行通信的连接的类型bluetooth | cellular | ethernet | none | wifi | wimax | other | unknown
downlink有效带宽估算(单位:兆比特/秒)number
downlinkMax最大下行速度(单位:兆比特/秒)number
saveData用户代理是否设置了减少数据使用的选项boolean
effectiveType网络连接的类型slow-2g | 2g | 3g | 4g

更多信息参考:MDN NetworkInformation

function getConnectionProperty(): NetworkState {
  const c = getConnection();
  if (!c) return {};
  return {
    rtt: c.rtt,
    type: c.type,
    saveData: c.saveData,
    downlink: c.downlink,
    downlinkMax: c.downlinkMax,
    effectiveType: c.effectiveType,
  };
}

useEffect 中,分别监听 online, offline, change 三个事件。

function useNetwork(): NetworkState {
  const [state, setState] = useState(() => {
    return {
      since: undefined,
      online: navigator?.onLine,
      ...getConnectionProperty(),
    };
  });

  useEffect(() => {
    const onOnline = () => {
      setState((prevState) => ({
        ...prevState,
        online: true,
        since: new Date(),
      }));
    };

    const onOffline = () => {
      setState((prevState) => ({
        ...prevState,
        online: false,
        since: new Date(),
      }));
    };

    const onConnectionChange = () => {
      setState((prevState) => ({
        ...prevState,
        ...getConnectionProperty(),
      }));
    };

    window.addEventListener(NetworkEventType.ONLINE, onOnline);
    window.addEventListener(NetworkEventType.OFFLINE, onOffline);

    const connection = getConnection();
    connection?.addEventListener(NetworkEventType.CHANGE, onConnectionChange);

    return () => {
      window.removeEventListener(NetworkEventType.ONLINE, onOnline);
      window.removeEventListener(NetworkEventType.OFFLINE, onOffline);
      connection?.removeEventListener(NetworkEventType.CHANGE, onConnectionChange);
    };
  }, []);

  return state;
}

useToggle

默认为 boolean 切换

默认为 falsesetLeft 设置默认值,setRight,是否传入第二个参数,如果传入第二个参数,那么就设置为第二个参数,否则设置默认参数的反值。

function useToggle<D, R>(defaultValue = false, reverseValue) {
  const [state, setState] = useState(defaultValue);

  const actions = useMemo(() => {
    const reverseValueOrigin = (reverseValue === undefined ? !defaultValue : reverseValue);

    const set = (value) => setState(value);
    const setLeft = () => setState(defaultValue);
    const setRight = () => setState(reverseValueOrigin);

    return {
      set,
      setLeft,
      setRight,
    };
  }, []);

  return [state, actions];
}

toggle 对两个值之间的切换。

const toggle = () => setState((s) => (s === defaultValue ? reverseValueOrigin : defaultValue));

Example

export default () => {
  const [state, { toggle, set, setLeft, setRight }] = useToggle('Hello', 'World');

  return (
    <div>
      <p>Effects:{state}</p>
      <p>
        <button type="button" onClick={toggle}>
          Toggle
        </button>
        <button type="button" onClick={() => set('Hello')} style={{ margin: '0 8px' }}>
          Set Hello
        </button>
        <button type="button" onClick={() => set('World')}>
          Set World
        </button>
        <button type="button" onClick={setLeft} style={{ margin: '0 8px' }}>
          Set Left
        </button>
        <button type="button" onClick={setRight}>
          Set Right
        </button>
      </p>
    </div>
  );
};