react 面试知识点总结

2025-07-14

1. React 组件通信方式

  • 通过props向子组件传递数据
  • 通过回调函数向父组件传递数据
  • 使用 refs调用子组件暴露的方法
    import React, { useRef, forwardRef, useImperativeHandle } from 'react'
 
    // 子组件
    const Child = forwardRef((props, ref) => {
        // 暴露方法给父组件
        useImperativeHandle(ref, () => ({
            sayHello() {
                alert('Hello from Child Component')
            }
        }))
 
        return <div>Child Component</div>
    })
 
    // Parent
    const childRef = useRef(null)
    const handleClick = () => {
        if (childRef.current) {
            childRef.current.sayHello()
        }
    }
 
    return (
        <div>
            <Child ref={childRef} />
            <button onClick={handleClick}>Call Child method</button>
        </div>
    )
  • 通过Context进行跨组件通信
  • 使用状态管理库进行通信(redux, mbox, zustand)

2. React 有哪些内置 Hooks ?

  • useState: 用于在函数组件中添加局部状态
  • useReducer: 用于管理复杂的状态逻辑,类似于 Redux 的 reducer
  • useEffect: 用于在函数组件中执行副作用操作(如数据获取、订阅、手动 DOM 操作等)异步进行
  • useLayoutEffect: 与 useEffect 类似,但在 DOM 更新后同步执行,适用于需要直接操作 DOM 的场景,同步进行
  • useContext: 用于访问 React 的上下文(Context)
  • useRef: 用于创建一个可变的引用对象,通常用于访问 DOM 元素或存储可变值
  • useMemo: 用于计算缓存结果,避免在每次渲染时都重新计算
  • useCallback:用于缓存回调函数,避免每次渲染时都创建新的回调
  • useImperativeHandle: 用于自定义暴露给父组件的实例值,通常与 forwardRef 一起使用

3.React 项目可做哪些性能优化?

  • useMemo: 用于计算昂贵的计算结果,避免在每次渲染时重复计算
  • useCallback: 用于缓存回调函数,避免在每次渲染时创建新的函数实例
  • React.memo: 是一个高阶组件,用于缓存组件的渲染结果,避免在 props 未变化时重新渲染
  const MyComponent = React.memo(({ value }) => {
  console.log('MyComponent rendered')
  return <div>{value}</div>
})
 
function ParentComponent() {
  const [count, setCount] = useState(0)
 
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <MyComponent value="Hello" /> {/* 不会因 count 变化而重新渲染 */}
    </div>
  )
}

4. 为什么说 react 数据是不可变的?

1. 什么是不可变数据?

不可变数据是指对数据的修改不会改变原数据本身,而是返回一个新的副本

2. 高效的 diff 算法需要

React每次组件更新时都会执行“浅比较”(比较引用的地址),来判断状态是否变化

话术

在 React 中我们强调“数据不可变”,是为了配合其虚拟 DOM 的高效 diff 算法。React 通过浅比较来判断状态是否变化,因此我们每次更新 state 时应返回一个新的对象或数组。如果直接修改原始数据,React 可能无法检测到变化,从而跳过更新。这会导致 UI 不一致或 Bug。因此,在实际开发中我始终使用不可变的方式更新状态,比如使用 … 展开符、map 或借助 immer

5. useEffect 和 useLayoutEffect 的区别

1. 执行时机
  • useEffect是在浏览器绘制完成后异步执行
  • useLayoutEffect是在DOM更新之后,但是在浏览器绘制之前执行
2. 使用场景
  • useEffect 适用于大多数副作用操作,如数据获取,订阅,手动 dom 操作等,因为这些操作通常不需要阻塞浏览器的渲染
  • useLayout 适用于需要在浏览器绘制前的同步操作,如测量 dom元素,同步更新 dom 等
3. 总结
  • useEffect:异步执行,不阻塞渲染,适合大多数副作用操作
  • useLayoutEffect:同步执行,阻塞渲染,适合需要在绘制前同步完成的副作用操作