在当今,React的钩子写法已经逐渐成为了一种主流开发模式,本文将介绍几种在React中常用的钩子
- useState
可以用来双向绑定,创建需要监听变化并且使用的数据
使用该钩子定义时,参数可以是一个直接定义好的变量,也可以是一个函数,函数返回什么,初始状态就是什么,函数只会被调用一次,用在初始值是动态值的情况下(props)
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
- useRef
用于获取操作DOM
可以存储上一次渲染的值,用useRef创建一个对象来存储setState前的旧值
import { useRef } from "react";
/**
* 1、useRef生成ref对象 绑定到dom标签上
* 2、DOM可用时,ref.current获取DOM,渲染完毕之后DOM生成之后才可用
*/
function App() {
const inputRef = useRef(null);
const showDom = () => {
console.log(inputRef.current);
};
return (
<div className="App">
<input type="text" ref={inputRef} />
<button onClick={showDom}>获取DOM</button>
</div>
);
}
也可以用于保存数据,特点是跨组件周期,组件重新渲染的时候还会存在,确保不会丢失
import React, { useRef, useEffect, useState } from 'react'
export default function ref() {
const [count, setCount] = useState(0)
const timerId = useRef()
useEffect(() => {
timerId.current = setInterval(() => {
setCount(count => count + 1)
}, 1000)
}, [])
const stopCount = () => {
console.log(timerId);
clearInterval(timerId.current)
}
return (
<div>
{count}
<button onClick={stopCount}>停止</button>
</div>
)
}
- useEffect
这个钩子在我们开发的时候特比较常用,所对应的情况也比较多一点,可以看作类组件挂载完成之后、组件数据更新完成之后、组件卸载之前去执行,主要分为以下几种情况
- 没有依赖项
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(111);
});
return (
<div>
<button onClick={() => setCount(count + 1)}>+{count}</button>
</div>
);
}
- 空数组依赖
const URL = "http://geek.itheima.net/v1_0/channels";
function App() {
const [list, setList] = useState([]);
useEffect(() => {
// 额外的操作,获取频道列表
async function getList() {
const res = await fetch(URL);
const list = await res.json();
console.log(list);
setList(list.data.channels);
}
getList();
}, []);
return (
<div>
this is app
{list.map((i) => (
<li key={i.id}>{i.name}</li>
))}
</div>
);
}
- 添加特定的依赖项
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(111);
},[count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>+{count}</button>
</div>
);
}
最后,我们在使用完成后,还应该清除对应的副作用,最常见的时机是在组件卸载时自动执行
function Son() {
useEffect(() => {
const timer = setInterval(() => {
console.log("定时器执行中...");
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
return <div>this is son</div>;
}
function App() {
const [show, setShow] = useState(true);
return (
<div>
{show && <Son></Son>}
<button onClick={() => setShow(false)}>卸载Son组件</button>
</div>
);
}
- useMemo
该钩子属于React性能优化中的一环,可以对数据进行缓存
类似于Vue中的计算属性,可以监听某个值的变化,根据变化值重新计算新值
会缓存计算结果,如果检测到值没有变化,即时组件重新渲染,也不会重新计算,可以有助于避免在每个渲染上浪费计算
import React, { useMemo } from 'react';
function ExpensiveCalculation({ num }) {
const calculateFactorial = (n) => {
console.log('Calculating factorial...');
return n <= 1 ? 1 : n * calculateFactorial(n - 1);
};
const factorial = useMemo(() => calculateFactorial(num), [num]);
return (
<div>
<h2>Factorial of {num}: {factorial}</h2>
</div>
);
}
- useCallback
用来缓存函数,使组件渲染的时候得到相同的函数实例,避免函数在组件重新渲染时重新创建
import React, { useState, useCallback } from 'react';
function Child({ onClick }) {
console.log('Child component rendered');
return <button onClick={onClick}>Click Me</button>;
}
function Parent() {
const [count, setCount] = useState(0);
// 使用 useCallback 避免函数在每次渲染时重新创建
const handleClick = useCallback(() => {
alert('Button clicked!');
}, []);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child onClick={handleClick} />
</div>
);
}
- useReducer
让函数组件保存状态的方式,与usestate钩子相比,结合了usestate和redux的优点,比如说在父组件想要修改子组件数据的时候,就不需要传递方法了,可以直接吧dispatch传递过去进行修改使用(通过props进行传递即可)
import { useReducer } from 'react'
function App() {
const reducer = (state, action) => {
switch (action.type) {
case 'plus':
return state + 1;
case 'des':
return state - 1;
default:
return state;
}
}
const [count, dispatch] = useReducer(reducer, 0)
return (
<>
<div className="card">
<button onClick={() => dispatch({ type: "plus" })}>
+1
</button>
{count}
<button onClick={() => dispatch({ type: "des" })}>
-1
</button>
</div>
</>
)
}
- useContext
在跨组件层级获取数据时简化数据的代码(App -> Foo)
import React, { useContext, useState } from 'react';
// 1. 创建 Context
const UserContext = React.createContext();
function App() {
const [user, setUser] = useState({ name: 'Alice', age: 25 });
return (
// 2. 使用 Provider 共享数据
<UserContext.Provider value={user}>
<UserProfile />
</UserContext.Provider>
);
}
function UserProfile() {
// 3. 在子组件中使用 useContext 获取 Context 的值
const user = useContext(UserContext);
return (
<div>
<h2>User Profile</h2>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
</div>
);
}
export default App;