useState
-
作用:
-
让函数组件像类组件一样拥有自己的状态
javascriptimport React, { useState } from 'react'; function Example() { const [count, setCount] = useState(() => { // 模拟复杂的计算 const initialValue = 2 * 3; return initialValue; }); setCount((oldValue)=>{ return setCount+1; }) return ( <div> <p>初始值为: {count}</p> </div> ); } export default Example;
-
参数说明:
-
useState
:接收一个参数,作为状态的初始值,参数有两种形式,静态和动态- 静态值:直接传入一个具体的值作为状态的初始值,如字符串、数字等
- 动态值:传入一个计算函数,计算函数的返回值会作为状态的初始值
-
setCount
:接收一个参数,用来更新当前状态,参数也有两种形式,静态和动态- 静态值:传入也给值,用来替换原状态的值
- 动态值:传入一个函数,函数接收一个参数(旧的状态值),函数的返回值用来替换原状态值
-
-
useEffect
-
写法1:useEffect(callback)
- 组件第一次渲染完毕之后,执行callback,等价于componentDidMount
- 在每次组件更新完毕之后,也会执行callback,等价于componentDidUpdate
-
写法2:useEffect(callback, [])
- 只有在第一次渲染完毕之后,才会执行callback,以后每次更新完毕,不再执行
- 类似于componentDidMount
-
写法3:useEffect(callback, [依赖状态1,依赖状态2,...])
- 第一次渲染完毕之后,会执行callback
- 当某一个或者多个依赖发生变化时,callback会执行
- 如果组件更新,但是依赖没有变化,callback不会执行
-
写法4:
scsslet [state,setSate] = useState(0) useEffect(()=>{ //1、返回的内部函数,会在组件释放的时候执行 //2、最常见的用法就是在这个函数里清除副作用 return ()=>{ console.log(state);//这里打印的state是组件更新之前的状态值 } })
- 与
写法1
的执行一样,但是内部函数的执行时机见上面代码注释
- 与
useLayoutEffect与useEffect的区别
- useLayoutEffect是同步执行的,会在阻塞浏览器的渲染,会在 DOM 更新完成后,但是浏览器绘制之前执行。可以做:获取 DOM 的宽高、修改样式等操作;以防止页面出现闪烁、抖动,提高用户体验。由于其会阻塞页面的绘制,所有需要谨慎使用。
- useEffect是异步执行的,不会阻塞浏览器的渲染,用户可以先看到页面的更新,然后
useEffect
的回调函数再开始执行。所有它比较适合处理一些不影响页面渲染的副作用,比如请求数据等。
useMemo
用来缓存复杂计算的结果,只要依赖项没有发生变化,结果就不会重新计算,可以提高性能。
ini
const memoizedValue = useMemo(() => {
// 进行一些复杂的计算
return computedValue;
}, [dependency1, dependency2, ...]);
-
参数:
- 参数1:传入回调函数,组件初次渲染时调用,当依赖项发生变化时重新调用,返回计算的结果,会作为useMemo的返回结果保存起来
- 参数2:传入一个数组,数组元素是依赖项,当任意一个依赖项发生改变时,useMemo都会重新调用回调函数,计算结果;如果传入的是一个空数组
[]
,则useMemo的回调函数只会在组件初次渲染时调用一次;如果不传递第二个参数,组件每次渲染都会执行一次回调函数,也就失去了使用useMemo来优化性能的意义。
-
返回值:useMemo返回的是回调函数的返回值,并将这个值缓存起来。
useMemo与useEffect的区别
-
参数
- useMemo与useEffect的参数一样
-
返回值
- useMemo返回传入回调函数的返回值,并把这个值缓存起来,避免不必要的重复计算
- useEffect可以返回一个清理函数,在组件卸载或下一次副作用执行之前调用,用于清除副作用(清除定时器、取消事件订阅等)
-
执行时机
- useEffect渲染之后异步执行,也就是说组件渲染完成,页面更新到屏幕上,然后useEffect的回调函数才会执行;为了避免副作用阻塞页面的渲染过程。
- useMemo在渲染期间同步执行,当组件渲染时,useMemo会立即检查依赖项是否发生变化,如果没有发生变化,就直接返回之前的结果,如果发生了变化,就重新计算结果并且更新缓存。
-
应用场景
- useEffect应用处理副作用操作,比如获取数据、事件订阅、定时器、修改DOM等
- useMemo用来处理复杂计算,并且缓存结果,提高性能。
useCallback
函数组件每次重新渲染时,其内部定义的函数都会被重新创建;如果这个函数被传递给子组件,可能会导致子组件不必要的更新,即使函数的逻辑并没有发生变化;useCallbaack可以帮我们记住函数的引用,只有当依赖项发生变化时,才会重新创建函数,从而避免子组件不必要的渲染。
javascript
import React, { useState, useCallback } from 'react';
// 子组件
const ChildComponent = React.memo(({ onClick }) => {
return <button onClick={onClick}>点击我</button>;
});
function ParentComponent() {
const [count, setCount] = useState(0);
// 使用 useCallback 记忆化函数
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>计数: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
}
export default ParentComponent;
useCallback与useMemo对比
-
参数
- useCallback与useMemo的参数一样
-
作用
- useCallback用来记忆函数的引用
- useMemo用来缓存计算结果
- 都可以用来优化性能
useContext
react应用中的数据一般是通过props来传递的,但是如果组件层级非常深的情况下,使用起来比较繁琐,useContext结合React.createContext,可以在任意下级组件中共享数据,不需要再层层传递。
- 创建context
javascript
import React from 'react';
// 创建一个上下文对象,初始值为 null
const MyContext = React.createContext(null);
export default MyContext;
-
提供上下文数据
javascriptimport React from 'react'; import MyContext from './MyContext'; const ParentComponent = () => { const sharedData = { message: 'Hello from context', count: 10 }; return ( <MyContext.Provider value={sharedData}> {/* 子组件 */} <ChildComponent /> </MyContext.Provider> ); }; export default ParentComponent;
-
子组件中使用useContext
javascriptimport React, { useContext } from 'react'; import MyContext from './MyContext'; const ChildComponent = () => { // 使用 useContext 获取上下文数据 const contextData = useContext(MyContext); return ( <div> <p>{contextData.message}</p> <p>Count: {contextData.count}</p> </div> ); }; export default ChildComponent;
useReducer
它是 useState
的替代方案,适用于管理复杂的状态逻辑;
scss
const [state, dispatch] = useReducer(reducer, initialArg, init);
-
参数:
reducer
:是一个纯函数,接收两个参数:当前状态state
和一个动作action
,并返回一个新的状态。其形式通常为(state, action) => newState
。initialArg
:初始状态值,或者用于初始化状态的参数。init
(可选):是一个初始化函数,用于惰性初始化状态。如果提供了init
函数,初始状态将是init(initialArg)
的返回值。
-
返回值
state
:当前状态值dispatch
:一个函数,用于触发状态更新,接收一个动作action
作为参数。
-
使用
javascriptimport React, { useReducer } from 'react'; // 定义 reducer 函数 const counterReducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; } }; function Counter() { // 使用 useReducer 初始化状态 const [state, dispatch] = useReducer(counterReducer, { count: 0 }); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> </div> ); } export default Counter;
useRef
-
保存可变值 :它可以创建一个可变的对象,在组件的整个生命周期内保持不变。每次组件重新渲染时,
useRef
返回的对象都是同一个,你可以通过修改该对象的current
属性来存储和读取数据,并且不会触发组件的重新渲染。 -
获取 DOM 节点 :可以通过
useRef
来引用 DOM 元素,从而可以在代码中直接操作该 DOM 元素,例如获取元素的尺寸、滚动位置等。javascriptimport React, { useRef } from 'react'; function Example() { const inputRef = useRef(null); const focusInput = () => { // 通过 ref 获取 DOM 节点并调用其方法 inputRef.current.focus(); }; return ( <div> <input ref={inputRef} type="text" /> <button onClick={focusInput}>聚焦输入框</button> </div> ); } export default Example;
forwardRef
是 React 提供的一个高阶组件,用于在组件之间转发 ref
。在 React 中,ref
是一种访问 DOM 节点或组件实例的方式,但默认情况下,组件不能直接将 ref
传递给子组件。forwardRef
可以打破这种限制,允许父组件将 ref
传递给子组件,从而让父组件可以访问子组件的 DOM 节点或调用子组件的方法。
useImperativeHandle
useImperativeHandle
通常与forwardRef
一起使用,用于自定义通过ref
暴露给父组件的实例值。默认情况下,当使用ref
引用一个组件时,父组件可以访问该组件的所有实例属性和方法,但有时候我们可能只想暴露部分特定的属性或方法,这时就可以使用useImperativeHandle
来实现。