前端框架:react

249 阅读2分钟

1.hooks使用规则

Hooks can only be called inside the body of a function component

a.只在最顶层使用 Hook
b.不要在循环,条件或嵌套函数中调用 Hook

c.只在 React 函数中调用 Hook, 不要在普通的 JavaScript 函数中调用 Hook。

✅ 在 React 的函数组件中调用 Hook
✅ 在自定义 Hook 中调用其他 Hook
遵循此规则,确保组件的状态逻辑在代码中清晰可见。

2.hooks原理

  • 为什么只能在函数最外层调用 Hook,不要在循环、条件判断或者子函数中调用?

  • 为什么 useEffect 第二个参数是空数组,就相当于 ComponentDidMount ,只会执行一次?

  • 自定义的 Hook 是如何影响使用它的函数组件的?

  • Capture Value 特性是如何产生的?

3.测试

react-dom/test-utils,react-test-renderer,我们在测试中应该怎么选择测试工具呢。

再做选择前,首先我们聊聊,什么是renderer。react最早是被用来开发网页的,所以早期React库中还包含了大量和DOM相关的逻辑。后来React的设计思想慢慢被迁移到其它场景,最被人们熟知的莫过于React Native了。为了灵活性和扩展性,React的代码被分拆为React核心代码与各种renderer。React自带了3个renderer,前两个是大家常见的:

  • react-dom 负责将组件渲染到浏览器页面中。
  • react-native-renderer 负责将组件渲染成原生场景中的各种View
  • react-test-renderer 负责将组件输出成JSON对象以方便我们便利、断言或是进行snapshot测试

这里有一个各种renderer列表

react-dom/test-utils从名称可以看出这个库是包含在react-dom中的。所以他只是react-dom的辅助测试工具。该库中的方法主要是帮助我们遍历ReactDom生成的DOM树,方便我们编写断言。使用该库时必须提供一个DOM环境,这个DOM环境可以是jsdom模拟环境

如何选择:简单来说

  • 如果需要测试事件(click,change,blur等),使用react-dom/test-utils
  • 其他时候使用更简单、更灵活的react-test-renderer 

react-test-renderer分为:

  • shallow render:组件只会被render一层(children中的React组件不会被render)
  • full render:组件会被完全render

其中Enzyme的底层其实也是基于react-test-renderer和react-dom/test-utils的,但它在二者的基础上进行了分装提供了更加简单易用的查询、断言方法。在Enzyme中提供了三种render模式:

  • Shadow Rendering 对应 react-test-renderer/shallow
  • Full DOM Rendering 对应 react-dom/test-utils
  • Static Rendering 对应 react-test-renderer

4.useState同步异步

异步更新,同步执行

5.合成事件

6.自定义hook

1. useDebounce

import { useRef, useCallback, useEffect } from 'react';interface IPoint<S> {  func: (args: S) => void;  timer: NodeJS.Timeout;}// 当事件触发后,一定时间内不再触发该事件,而如果重新触发,就会重新开始延长,debounce也分为两种,在延长周期前生效,和周期末生效function useDebounce<S>(func: (args: S) => void, wait: number, isImmediate = false) {  const a: IPoint<S> = { func, timer: null };  const { current } = useRef(a);  useEffect(() => {    current.func = func;  }, [current, func]);  return useCallback(    (...args) => {      if (current.timer) clearTimeout(current.timer); // 清除之前的时间延迟执行      if (isImmediate) {        if (!current.timer) {          func.apply(this, args);          current.timer = null;        }        current.timer = setTimeout(() => {          current.timer = null;        }, wait);      } else {        current.timer = setTimeout(() => {          func.apply(this, args);        }, wait);      }    },    [current, func, isImmediate, wait],  );}export default useDebounce;

2.  useSyncState

import { useState, useRef, useCallback } from 'react'

const useSyncState = ( initVal ) => {
    // 状态值
    const [ state, setState ] = useState(initVal)

    // 变量值
    let current = useRef(initVal)

    // 同步 state 和 current 的值
    const setState = useCallback(( changeVal ) => {
        current.current = changeVal
        setState(changeVal)
    }, [])

    // 返回一个数组
    return [ state, setState, current ]
}

3. useCountdown

import { useCallback, useEffect, useReducer, useState } from 'react';const useCountdown = (initCount: number, interval: number, callback?: () => void) => {    const [count, setCount] = useState(initCount - Date.now());    // 一个增长的计时器,用于重置倒计时    const [ignored, forceUpdate] = useReducer(x => x + 1, 0);    const reset = useCallback(() => {        setCount(initCount - Date.now());        forceUpdate();    }, [initCount]);    useEffect(() => {        const time = setInterval(() => {            setCount(preCount => {                if (initCount <= Date.now()) {                    clearInterval(time);                    if (callback) {                        const t = setTimeout(() => {                            callback(); // NOTE:魔法数字100,延迟执行,防止组件销毁的比组件内部操作还早,从而出现警告                            clearTimeout(t);                        }, 100);                    }                    return 0;                }                // BUGFIX:解决后台运行的时候,倒计时停止                return initCount - Date.now();            });        }, interval);        return () => {            clearInterval(time);        };    }, [interval, ignored]);    return [count, reset] as const;};

前端面试题:blog.csdn.net/qq\_1654682…