react-use 部分源码分析(下)

简介: 2019 年写的分析,慎重观看。不过其中的思路还是值得学习的。

useStartTyping



document注册keydown事件,检查事件触发时activeElement是不是input和textarea以及是不是有contenteditable属性,以及检查keyCode的值是不是在有效范围,排除ctl alt等等。


const isFocusedElementEditable = () => {
  const { activeElement, body } = document;
  if (!activeElement) {
    return false;
  }
  // If not element has focus, we assume it is not editable, too.
  if (activeElement === body) {
    return false;
  }
  // Assume <input> and <textarea> elements are editable.
  switch (activeElement.tagName) {
    case 'INPUT':
    case 'TEXTAREA':
      return true;
  }
  // Check if any other focused element id editable.
  return activeElement.hasAttribute('contenteditable');
};
const isTypedCharGood = ({ keyCode, metaKey, ctrlKey, altKey }: KeyboardEvent) => {
  if (metaKey || ctrlKey || altKey) {
    return false;
  }
  // 0...9
  if (keyCode >= 48 && keyCode <= 57) {
    return true;
  }
  // a...z
  if (keyCode >= 65 && keyCode <= 90) {
    return true;
  }
  // All other keys.
  return false;
};
const useStartTyping = (onStartTyping: (event: KeyboardEvent) => void) => {
  useLayoutEffect(() => {
    const keydown = event => {
      !isFocusedElementEditable() && isTypedCharGood(event) && onStartTyping(event);
    };
    document.addEventListener('keydown', keydown);
    return () => {
      document.removeEventListener('keydown', keydown);
    };
  }, []);
};
复制代码


useMeasure



  1. ResizeObserver 采用了 resize-observer-polyfill, 高阶组件react-virtualized-auto-sizer 也能做到类似功能监听功能
  2. 利用函数ref属性
  3. useState使用函数参数初始化ResizeObserver实例


const useMeasure = <T>(): [(instance: T) => void, ContentRect] => {
  const [rect, set] = useState({
    width: 0,
    height: 0,
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  });
  const [observer] = useState(
    () =>
      new ResizeObserver(entries => {
        const entry = entries[0];
        if (entry) {
          set(entry.contentRect);
        }
      })
  );
  const ref = useCallback(
    node => {
      observer.disconnect();
      if (node) {
        observer.observe(node);
      }
    },
    [observer]
  );
  return [ref, rect];
};
export default useMeasure;
复制代码


useClickAway



HTML Nodecontains方法, 判断节点是否为该节点的后代节点。


const useClickAway = (
  ref: RefObject<HTMLElement | null>,
  onClickAway: (event: KeyboardEvent) => void,
  events: string[] = defaultEvents
) => {
  const savedCallback = useRef(onClickAway);
  useEffect(() => {
    savedCallback.current = onClickAway;
  }, [onClickAway]);
  useEffect(() => {
    const handler = event => {
      const { current: el } = ref;
      el && !el.contains(event.target) && savedCallback.current(event);
    };
    for (const eventName of events) {
      on(document, eventName, handler);
    }
    return () => {
      for (const eventName of events) {
        off(document, eventName, handler);
      }
    };
  }, [events, ref]);
};
复制代码


useCss



借用了 CSS-in-JS library nano-css

nano-css本身使用的是 CSSStyleSheet.insertRule


const useCss = (css: object): string => {
  const className = useMemo(() => 'react-use-css-' + (counter++).toString(36), []);
  const sheet = useMemo(() => new nano.VSheet(), []);
  useLayoutEffect(() => {
    const tree = {};
    cssToTree(tree, css, '.' + className, '');
    sheet.diff(tree);
    return () => {
      sheet.diff({});
    };
  });
  return className;
};
复制代码


useDrop



监听document的dragover,dragenter,dragleave,dragexit,drop,paste等事件。


useDropArea



传入事件监听函数,返回bound各种方法以及是否hover属性。 boud方法需要挂载到节点,那么突破口就是bound。


通过bound注入事件,然后在事件里面拦截,再调用传入的监听函数。


看看调用


import {useDropArea} from 'react-use';
const Demo = () => {
  const [bond, state] = useDropArea({
    onFiles: files => console.log('files', files),
    onUri: uri => console.log('uri', uri),
    onText: text => console.log('text', text),
  });
  return (
    <div {...bond}>
      Drop something here.
    </div>
  );
};
复制代码


useFullscreen



引入了库 screenfull 。 基本就是request全屏然后,监听change事件。

当然对video进行了额外的处理。


const onWebkitEndFullscreen = () => {
      video!.current!.removeEventListener('webkitendfullscreen', onWebkitEndFullscreen);
      onClose();
    };
    const onChange = () => {
      if (screenfull) {
        const isScreenfullFullscreen = screenfull.isFullscreen;
        setIsFullscreen(isScreenfullFullscreen);
        if (!isScreenfullFullscreen) {
          onClose();
        }
      }
    };
    if (screenfull && screenfull.enabled) {
      try {
        screenfull.request(ref.current);
        setIsFullscreen(true);
      } catch (error) {
        onClose(error);
        setIsFullscreen(false);
      }
      screenfull.on('change', onChange);
    } else if (video && video.current && video.current.webkitEnterFullscreen) {
      video.current.webkitEnterFullscreen();
      video.current.addEventListener('webkitendfullscreen', onWebkitEndFullscreen);
      setIsFullscreen(true);
    } else {
      onClose();
      setIsFullscreen(false);
    }
复制代码


useSpeech



这个功能我以前不知道的说。

浏览器支持率居然将近 90%, Can i use |speechSynthesis

其实就用利用了window.speechSynthesis。 原生代码也就是


var utterance = new SpeechSynthesisUtterance('我们都是中国人'); 
window.speechSynthesis.speak(utterance)
复制代码


useWait



额,直接用的react-wait


相关文章
|
1月前
|
JSON 缓存 前端开发
【React】React原理面试题集锦
本文集合一些React的原理面试题,方便读者以后面试查漏补缺。作者给出自认为可以让面试官满意的简易答案,如果想要了解更深刻,可以点击链接查看对应的详细博文。在此对链接中的博文作者非常感谢🙏。
34 0
|
前端开发 JavaScript
React17源码解读—— 事件系统
读完本篇文章你将明白为什么是React的合成事件SyntheticEvent, 以及React如何模拟浏览器的捕获和冒泡。   在学习React的合成事件之前,我们先复习下浏览器的事件系统,以及代理委托。这对我理解React事件系统源码非常重要。   W3C 标准约定了一个事件的传播过程要经过以下 3 个阶段:
React17源码解读—— 事件系统
|
15天前
|
前端开发 JavaScript 算法
React原理
【4月更文挑战第4天】本文介绍了React的核心概念,包括jsx、React.createElement和fiber。jsx是React的语法糖,被转换为React.createElement生成虚拟DOM (vDOM)以优化性能。vDOM是轻量的数据结构,用于描述DOM状态。React通过fiber结构改进渲染性能,将同步任务拆分成小任务,利用requestIdleCallback在浏览器空闲时执行,确保流畅的用户体验。fiber是增强的vDOM,包含额外的引用指针。文章还提及了diff算法和hooks在React中的作用。
9 0
|
3月前
|
缓存 前端开发 JavaScript
React 面试题
React 面试题
115 0
|
3月前
|
缓存 前端开发 JavaScript
React 面试题2
React 面试题2
|
6月前
|
存储 JavaScript 前端开发
React-Redux-实现原理
React-Redux-实现原理
24 0
|
8月前
|
XML JavaScript 前端开发
react面试题大全三
react面试题大全三
|
8月前
|
JavaScript 前端开发 算法
【React常见面试题】
【React常见面试题】
60 0
|
9月前
|
存储 缓存 前端开发
你需要知道的 12 道 React 面试题
你需要知道的 12 道 React 面试题
|
10月前
|
前端开发 开发者 UED