目录
Hooks 相比 HOC 和 Render Prop 有哪些优点?
-
列举十个常用的 React 内置 Hooks。
- useState
- useEffect
- useContext
- useRef
- useParams
- useCallback
- useMemo
- useReducer
- useLayoutEffect
- useNavigate
-
为什么会有 React Hooks,他解决了哪些问题?
- 组件逻辑复用困难,在 React 之前,组件的逻辑复用主要通过高阶组件和渲染属性来实现,但这种方式会导致嵌套过深、代码冗余和难以理解。
- 类组件的限制,简化了对生命周期的理解和使用。可以将副作用操作封装到 useEffect 中,使得代码更集中、易于管理和组织。
- 难以理解和使用生命周期方法,简化了对生命周期的理解和使用。可以将副作用操作封装到 useEffect 中,使得代码更集中、易于管理和组织。
- 组件之间状态共享问题
-
React Hooks 如何模拟组件的生命周期?
-
useEffect
Hook:可以替代componentDidMount
、componentDidUpdate
和componentWillUnmount
生命周期函数。可以在函数组件中使用useEffect
来执行副作用操作,比如订阅事件、发送网络请求等。 -
useLayoutEffect
Hook:类似于useEffect
,但在浏览器绘制之前同步执行。一般情况下,可以使用useEffect
,只有在需要在 DOM 更新后立即执行代码时才会使用useLayoutEffect
。 -
useRef
Hook:可以用来获取持久引用,类似于类组件中的实例变量。可以在函数组件中使用useRef
来存储和更新可变值,而不会引起重新渲染。 -
useMemo
Hook:可以替代shouldComponentUpdate
生命周期函数。可以在函数组件中使用useMemo
来缓存计算结果,避免不必要的重复计算。 -
useCallback
Hook:可以替代shouldComponentUpdate
和componentWillUnmount
生命周期函数。可以在函数组件中使用useCallback
来缓存回调函数,避免不必要的重复创建。 -
useReducer
Hook:可以替代setState
方法,并且提供更复杂的状态管理。可以在函数组件中使用useReducer
来定义和更新复杂的状态逻辑。
-
-
如何自定义Hooks?
-
函数名称以
use
开头,例如useCustomHook
。 -
函数内部可以使用其他的 React Hooks 或自定义的 Hooks。
-
函数可以返回任何值,通常是一个包含状态、处理逻辑或效果的对象。
import { useState, useEffect } from 'react'; function useCounter(initialValue, step) { const [count, setCount] = useState(initialValue); useEffect(() => { document.title = `Count: ${count}`; }, [count]); const increment = () => { setCount(prevCount => prevCount + step); }; const decrement = () => { setCount(prevCount => prevCount - step); }; return { count, increment, decrement }; } // 在组件中使用自定义的 Hook function Counter() { const { count, increment, decrement } = useCounter(0, 1); return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> ); }
在上述示例中,
useCounter
是一个自定义的 Hook。它使用了useState
来定义计数器的状态,并使用useEffect
来更新文档标题。最后,它返回一个包含计数器值以及增加和减少计数器的函数的对象。在组件中使用自定义的 HookuseCounter
,就可以获取到这些值和函数,并在渲染过程中使用它们。
-
-
说一下 React Hooks 性能优化。
- 使用 useMemo 和 useCallback:useMemo 和 useCallback 都是用来缓存计算结果或回调函数的 Hook。
- 使用 React.memo 进行组件的浅层比较:React.memo 是一个高阶组件,用于包裹函数组件并对其进行浅层比较。使用 React.memo 可以避免由于父组件状态的改变而引起无意义的子组件渲染。
- 使用 useReducer 替代 useState:useReducer 提供了更灵活的状态管理方式,能够处理更复杂的状态逻辑,避免直接在组件中定义大量的 setState 函数
- 使用 React.lazy 和 Suspense 进行组件的懒加载:通过使用 React.lazy 和 Suspense,可以将组件的加载延迟到需要的时候,减少初始加载时间。
-
使用数据分离:将组件的状态和逻辑进行拆分,使每个拆分出来的组件只关注特定的数据和逻辑。这样可以避免因为某个状态改变而导致整个组件重新渲染。
-
使用 useRef:可以获取持久引用,并在多次渲染之间保持稳定。通过使用
useRef
,可以避免在重新渲染时重新创建对象,提高性能。
-
使用 React Hooks 遇到哪些坑?
- 不要在循环、条件语句或嵌套函数中使用 Hook:React Hooks 的规则要求在函数组件的顶层使用 Hook,不能在循环、条件语句或嵌套函数中使用。
- 使用正确的依赖数组:在 useEffect 和 useCallback 中,需要传递一个依赖数组,指定在依赖项发生变化时才重新执行副作用操作或创建新的回调函数。
- 不要滥用 useMemo 和 useCallback:虽然 useMemo 和 useCallback 可以优化性能,但滥用这两个 Hook 可能会导致代码复杂化。
-
理解闭包陷阱:由于闭包特性,在循环中使用 Hook 可能会遇到意料之外的问题。为了解决这个问题,可以使用额外的函数进行包装,以保证每次迭代都有独立的作用域。
-
副作用操作可能会多次执行:useEffect 中执行副作用操作时,需要注意其执行频率。确保副作用操作不会引入不必要的性能开销或产生副作用。
-
注意组件更新时的副作用操作:在使用 useEffect 时,需要考虑副作用操作的触发条件。
-
组件拆分可能导致重复渲染:由于 React 的渲染机制,某些情况下拆分组件可能导致不必要的重复渲染,从而影响性能。可以使用 React.memo 进行浅层比较来避免这个问题。
-
Hooks 相比 HOC 和 Render Prop 有哪些优点?
- 更简洁清晰的代码
- 更好的可读性和维护性
- 避免命名冲突和组件包裹
- 更灵活的逻辑复用
- 更灵活的逻辑复用