useState
用来声明状态变量,括号里面参数为初始值。
const [ count , setCount ] = useState(0);
useEffect&&useLayoutEffect
注意点:异步执行
副作用钩子,useLayoutEffect和原来componentDidMount&componentDidUpdate一致,在react完成DOM更新后马上同步调用的代码(DOM修改后且浏览器渲染之前),会阻塞页面渲染。而useEffect是会在整个页面渲染完才会调用的代码。
//首次渲染,和count更新都会再次执行
const mounting = useRef(true);
useEffect(() => {
console.log('挂载componentDidmount')
// 模拟componentDidUpdate生命周期,而去掉初次渲染时调用的 componentDidMount
if (mounting.current) {
console.log("初次")
mounting.current = false;
return
}
// 卸载componentWillUnmount
return () => {
console.log('卸载componentWillUnmount')
}
}, [])
第二个参数传值情况:
- 不传 每次渲染后都执行清理或者执行effect,容易死循环。
- 传 [], 只运行一次的 effect(仅在组件挂载和卸载时执行),componentDidmount
- 传普通变量的数组[id,name],当id或者name变化时候会执行,componentDidUpdate;传对象 [{}],因为js中{}==={}为false,会死循环
可代替
- componentDidMount
- useEffect第二个参数[]时
- componentDidUpdate
- useEffect第二个参数[count]时,即只有count变化时候才会调用
- componentWillUnmount
操作方式:return一个匿名函数
useEffect(()=>{
console.log('index页面')
return ()=>{
console.log('离开index页面')
}
},[])
useContext
解决传值问题(context上下文),可祖孙级别传值,可实时监听能动态变化
useContent的参数一般是由createContext的创建,通过 CountContext.Provider 包裹的组件,才能通过 useContext 获取对应的值
不用hook方式
import React, {createContext} from 'react';
const ChildContext = createContext(20); //括号里可以传默认值
function Child() {
return (
<ChildContext.Consumer>
{/* 必须用函数返回 */}
{
val => <h1>值:{val}</h1>
}
</ChildContext.Consumer>
)
}
function LazyDemo() {
return (
<div className="App">
<ChildContext.Provider value={60}>
<Child></Child>
</ChildContext.Provider>
</div>
);
}
export default LazyDemo;
hook方式
import React, { useState, createContext, useContext } from 'react';
// 子组件传值
const CountContext = createContext();
function Counter(){
let count = useContext(CountContext)
return (<h2>{count}个</h2>)
}
function Example(){
const [count, setCount ] = useState(0)
return(
<div>
<p>{count}</p>
<button onClick={()=>{setCount(count+1)}}>Click me</button>
<CountContext.Provider value={count}>
<Counter/>
</CountContext.Provider>
</div>
)
}
export default Example;
useReducer 状态管理
- state:更新后的state值
- dispatch:可以理解为和useState的setState一样的效果
- reducer:可以理解为redux的reducer
- initialArg:初始值
- init:惰性初始化
import React, { useReducer} from 'react';
// useReducer
// 第一个值 (函数,第二个值初始值)
// 通过dispatch去更新值
function ReducerDemo(){
const [count, dispatch] = useReducer((state,action)=>{
switch(action){
case 'add':
return state + 1
case 'sub':
return state - 1
default:
return state
}
},0)
return(
<div>
<h2>现在的分数是{count}</h2>
<button onClick={()=>{dispatch('add')}}>Increment</button>
<button onClick={()=>{dispatch('sub')}}>Decrement</button>
</div>
)
}
export default ReducerDemo
可结合useContext实现redux,主要就是吧dispacth放在Provider中value中传递给子组件,让子组件可以使用dispacth
export const Color = props=>{
const [color, dispatch] = useReducer(reducer,'blue')
return (
<ColorContext.Provider value={{color,dispatch}}>
{props.children}
</ColorContext.Provider>
)
}
useRef
- 存放一些会发生变化的值,useRef 并不再单单是为了 DOM 的 ref 准备的,同时也会用来存放组件实例的属性。
const inputEl = useRef(null)
const [text, setText] = useState('哇哦')
const onButtonClick = ()=> {
inputEl.current.value = text
console.log(inputEl)
}
return (
<div>
<input ref={inputEl} type="text"></input>
<button onClick={onButtonClick}>展示文字</button>
</div>
)
- 存变量
因为在函数式组件里没有了 this 来存放一些实例的变量,所以 React 建议使用 useRef 来存放一些会发生变化的值,useRef 并不再单单是为了 DOM 的 ref 准备的,同时也会用来存放组件实例的属性。
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// 定时器
});
intervalRef.current = id;
// unmount时候清除定时器
return () => {
clearInterval(intervalRef.current);
};
});
}
useMemo 解决性能问题(缓存值)
如果说类组件的性能优化的方法是 shouldComponentUpdate 和 PureComponent,那么给函数组件做性能优化的就是这个 useMemo。
解决问题: 父组件传入一个值变化,导致子组件其他值也跟着重新渲染
//参数一:接受一个方法
//参数2: 数组 [状态] 只有这个状态变动 才会调用 前面的方法,,, 写请求用
const actionProcess1 = useMemo(()=>{
function changeProcess1(){
console.log('进程1动了')
return name+',进程1来了'
}
changeProcess1(name)
},[name])
useCallback解决性能问题(缓存方法)
useCallback 的作用在于利用 memoize 减少无效的 re-render,来达到性能优化的作用。缓存一个函数,常用于给子组件传递方法,避免不必要的更新,更多搭配React.Memo使用。
import React,{ useCallback,useState,useEffect } from 'react'
// 自定义hooks,用use开头命名,封装重复使用的代码,可以抽离出成一个模块,在多个场景下使用,提高代码的复用性
function useWinSize(){
//设置变量size:{}
const [size, setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})
// useCallback缓存方法 [] 只执行一次
const onResize = useCallback(()=>{
setSize({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight,
})
},[])
useEffect(()=>{
window.addEventListener('resize',onResize)
// // 销毁时
return ()=>{
window.removeEventListener('resize',onResize)
}
},[onResize])
return size
}
function Example(){
const size = useWinSize()
return (
<div>页面大小{size.width}*{size.height}</div>
)
}
export default Example
注意:当useEffect里面使用了外部的变量的情况下,需要在第二个数组参数中放入对应的变量,防止类似 React Hook useLayoutEffect has a missing dependency: ‘options’. Either include it or remove the dependency array react-hooks/exhaustive-deps 的一些检查提示、代码规范.
useMemo和useCallback
useMemo和useCallback接收的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于useMemo返回的是函数运行的结果,useCallback返回的是函数。
useCallback(fn, inputs) === useMemo(() => fn, inputs))