React Hooks
高阶组件为了复用,导致代码层级复杂
生命周期复杂
函数式组件,无状态组件=》又需要状态==》改成class成本高
React Hooks提供了一种在函数组件中使用状态(state)和其他 React 特性的方式,以取代传统的基于类的组件。
Hooks 只能在函数组件的顶层作用域中调用,不能在循环、条件语句或嵌套函数中使用。这是因为 React 需要根据 Hooks 的调用顺序来跟踪组件的状态和更新。
Hooks中没有this
useState
useState
保存组件状态 , setXxx会将整个函数组件重新执行
import React, { useState } from 'react'
export function App(){
const [ name, setname ] = useState('')
return(
<div>
{
console.log('name' ,name)
}
<button onClick={()=>{
setname('小明')
}}>点击</button>
</div>
)
}
/*
> name
---点击之后--
> name 小明
*/
useEffect
处理副作用
useEffect(()=>{
//其中逻辑立即执行一次
//如果在第二参数传递相应状态,改变时,会再次执行这个副作用回调(有点类似Vue的watch)
return ()=>{
// 销毁逻辑
}
},[])
//依赖的数组。空数组表示不依赖
可多次使用
useLayoutEffect
useLayoutEffect
和原来DidMount DidUpdat一致,在react完成DOM更新后马上同步调用代码
而useEffect
在整个页面渲染完才会调用(不会阻塞页面渲染)
假如要在Effect中进行DOM操作,最好使用LayoutEffect,避免页面抖动,只有一次回流重绘的代价
useCallback()
useState 可以记住状态
useCallback
is a React Hook that lets you cache a function definition between re-renders.
useCallback()
缓存函数
组件更新会导致组件内函数也相应更新。但是如果使用useCallback只在所依赖值改变后,再进行更新。
跟dependecies不相关的元素改变,不会导致这个记忆函数重新执行
import React, { useState, useCallback } from 'react'
export function App(){
const [ name, setname ] = useState('')
const fn = useCallback(()=>{
console.log('name1' ,name)
}, []) // 没有设置name依赖数据,记忆函数记忆第一次状态,不会更改回调里的数据
const fn2 = () => {
console.log('name2', name)
}
return(
<div>
{ /* 点击按钮 */ }
{
fn() // 怎么输出都为空
}
{
fn2() // 输出name属性
}
<button onClick={()=>{
setname('小明')
}}>点击</button>
</div>
)
}
useMemo
useMemo
记忆组件(类似vue计算属性)
useMemo is a React Hook that lets you cache the result of a calculation between re-renders.
会执行回调函数,并将回调的执行结果返回回来
import React, { useState, useMemo } from "react";
function getList(val?: number){
const arr = [1, 2, 3, 4]
if(val){
arr.push(val)
}
return arr
}
export default function APP() {
const [count, setcount] = useState(0);
const res = useMemo(()=> getList(count), [count]) //自动根据依赖计算属性
return (
<div>
<strong>{res}</strong>
<button onClick={() => {
setcount(2)
}}
>
点击
</button>
</div>
);
}
useRef()
useRef()
类似class 的createRef
如何保存临时变量(闭包):useState,useRef引用唯一变量
const myref = useRef()
...
<input ref={myref} />
...
{
myref.current
}
useContext
useContext
减少组件层级
上下文(Context)是 React 中一种跨组件层级共享数据的机制。通过上下文,可以避免通过组件层层传递 props 的方式来共享数据,使得组件之间的通信更加简洁和灵活。
import React, { useState, useContext } from "react";
const GlobalContext = React.createContext({} as any); //初始化传递一个空对象
function Child() {
// useContext 相当于之前的Consumer
const value = useContext(GlobalContext);
return (
<div>
<button
onClick={() => {
value.changeInfo("哈哈");
console.log("?", value.info);
}}
>
改变info
</button>
</div>
);
}
export default function APP() {
const [info, setinfo] = useState("一段初始化信息");
return (
<GlobalContext.Provider
value={{
info,
changeInfo: (val: any) => {
setinfo(val);
}
}}
>
<Child />
</GlobalContext.Provider>
);
}
useReducer
useReducer
(Redux)
外部管理集中状态 (类似vuex)
每次创建的reducer实例不是共享的
只能在hook中调用
配合useContext跨级通信实现状态共享
import React, { useContext, useReducer } from "react";
const GlobalContext = React.createContext({} as any); //初始化传递一个空对象
// 初始化共享状态
const initalState = {
info: "初始化文字"
};
// 分发逻辑
const reducer = (state: any, action: any) => {
const newState = { ...state }; //拷贝老状态
switch (action.type) {
case 1:
newState.info = action.value; //修改状态
return newState; //返回一个新的状态
}
};
export default function APP() {
const [state, dispatch] = useReducer(reducer, initalState);
return (
<GlobalContext.Provider
value={{
state,
dispatch
}}
>
<Child />
</GlobalContext.Provider>
);
}
function Child() {
// useContext 相当于之前的Consumer
const { state, dispatch } = useContext(GlobalContext);
return (
<div>
<button
onClick={() => {
dispatch({
type: 1,
value: "新的Info"
});
}}
>
改变info
</button>
<strong>{state.info}</strong>
</div>
);
}
视图逻辑与状态逻辑分离
自定义Hooks
两个函数共享逻辑时,我们会把他提取到第三个函数中
命名use开头,这样React会自动进行检查
(只是抽离逻辑,为了复用逻辑)
import React from "react";
// 模拟列表
function getList(val?: number){
const arr = [1, 2, 3]
if(val){
arr.push(val)
}
return arr
}
// 获取列表自定义Hooks
const useList = (val?: number) => {
return getList(val)
}
export default function APP() {
const list = useList(1)
return (
<div>
<ul>
{
list.map(item=><li key={item}> {item} </li>)
}
</ul>
</div>
)
}