1.state
- setState(obj,callback)
- 第一个参数:当 obj 为一个对象,则为即将合并的 state ;如果 obj 是一个函数
- 那么当前组件的 state 和 props 将作为参数,返回值用于合并新的 state。
- 第二个参数 callback :callback 为一个函数,函数执行上下文中可以获取当前 setState 更新后 的最新 state 的值,可以作为依赖 state 变化的副作用函数,可以用来做一些基于 DOM 的操作。
/* 第一个参数为function类型 */
this.setState((state,props)=>{ return { number:1 } })
/* 第一个参数为object类型 */
this.setState({ number:1 },()=>{ console.log(this.state.number) //获取最新的number })
2.useState
- state: 作为页面渲染的数据
- dispatch: 作为state的状态更新的函数
1.如果为值,直接赋值给新的state作为渲染条件
2.如果为函数,函数参数为当前state,新值为赋值给state的值 setState((state)=> state + 1) - initData:
1.可作为值进行传递,作为值传递的时为state默认值,
2.作为函数进行传递时,函数返回值为state默认值
// [ state , setState ] = useState(initData)
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
3.useEffect
useEffect又称副作用hooks。
作用:给没有生命周期的组件,添加结束渲染的信号。
执行时机:在渲染结束之后执行
- useEffect 第一个参数 callback, 返回的 destory , destory 作为下一次callback执行之前调用,用于清除上一次 callback 产生的副作用。
- 第二个参数作为依赖项,是一个数组,可以有多个依赖项,依赖项改变,执行上一次callback 返回的 destory ,和执行新的 effect 第一个参数 callback 。
- 在不接受第二个参数情况下,那么在第一次渲染完成之后和每次更新渲染页面的时候,都会调用
useEffect的回调函数,
import React, { useEffect, useState } from 'react';
const DataFetcher = () => {
const [data, setData] = useState(null);
useEffect(() => {
// 在组件挂载后执行副作用操作
fetchData().then((result) => {
setData(result);
});
// 在组件卸载前执行清理操作
return () => {
cleanup();
};
}, []);
return <div>{data ? <p>Data: {data}</p> : <p>Loading...</p>}</div>;
};
4.useLayoutEffect
与useEffect对比
- 相同点
- 1.第一个参数,接收一个函数作为参数
- 2.第二个参数,接收【依赖列表】,只有依赖更新时,才会执行函数
- 3.返回一个函数,先执行返回函数,再执行参数函数
- 不同点
- 执行时机不同。useLayoutEffect在DOM更新之后执行;
- useEffect在render渲染结束后执行。在测试代码中,useLayoutEffect执行永远在useEffect之前,这是因为DOM更新之后,渲染才结束或者渲染还会结束
import React, { useEffect, useState, useLayoutEffect } from 'react';
const DataFetcher = () => {
const [num, setNum] = useState(0)
//在类组件中用componentWillMount生命周期来实现
useLayoutEffect( () => {console.log('useLayoutEfffect')},[num])
useEffect( () => {console.log('
')},[num])
return (
<div onClick={ ()=>setNum( num => num+1 ) }> {num} </div>
)
};
5.useMemo
- 1.接收一个函数作为参数
- 2.同样接收第二个参数作为依赖列表(与useEffect、useLayoutEffect相似)
- 3.返回的是一个值。返回值可以是任何,函数、对象等都可以
- 4.使用场景有复杂计算逻辑优化、父子组件传值重新优化等;
对于复杂计算而言,使用useMemo包裹后,第一次计算后,会缓存的一个计算结果,只有在当依赖数组中的任何一个值发生变化时,计算函数将被重新计算,从而降低复杂计算带来的开销。例如在空依赖项的情况下,复杂计算只会在首次加载时执行。
import React, { useMemo } from 'react';
const = expensive => ({ value1, value2 }) {
const result = useMemo(() => {
console.log('calculating result');
return value1 * value2;
}, [value1, value2]);
return <div>{result}</div>;
}
6.useCallback
与useMemo相似,useCallback也是一个对于状态优化的hook,它接受一个回调函数和一个依赖数组,并返回一个缓存的回调函数。当依赖数组中的任何一个值发生变化时,缓存的回调函数将被更新。
- 不同点:
- useCallback是缓存的是一个函数,对传过来的回调函数优化,返回的是一个函数;useMemo返回值可以是任何,函数,对象等都可以。
- 复杂计算逻辑的场景不适合使用useCallback来缓存,因为传入的函数内容会不断执行。
- 相同点:
- useMemo与useCallback相同。接收一个函数作为参数,也同样接收第二个参数作为依赖列表
import React, { useState, useCallback } from 'react';
function Parent() {
const [num, setNum] = useState(0);
const handleClick = useCallback(() => {
setNum(num + 1);
}, [num]);
return (
<>
<Child onClick={handleClick} />
<span>{num}</span>
</>
);
}
function Child({ onClick }) {
return <button onClick={onClick}>Click me</button>;
}
7.useRef
注意:使用useRef的属性,不会主动触发页面重新渲染。
useRef 用于在函数组件中保存可变值的引用,所以我们可以用来存储可变值:比如有一个值需要在渲染过程中保留,但不会影响组件的 UI 或触发重新渲染,此时使用useRef 是一个不错的选择。
与usestate不同,useRef 主要用于访问和操作 DOM 或存储不触发重新渲染的可变值。它返回一个带有 current 属性的可变对象。
如下示例:
将 inputRef 使用useRef 进行包裹,并将其传入input的 ref 属性中,,此时我们就可以获取到input的 DOM 节点。
单击单击按钮时,将执行 handleClick 函数,并调用 input的 DOM 节点inputRef ,并唤起inputRef.current.focus聚焦() 方法进行input组件的focus聚焦。
import React, { useRef } from 'react';
function Input() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>Focus input</button>
</>
);
}
8.useContext
useContext是让子组件之间共享父组件传入的状态的。
- 需要引入useContext,createContext两个内容
- 通过createContext创建一个context
- Context.Provider来确定数据共享范围
- 通过value来分发内容
- 在子组件中,通过useContext(Context)来获取数据
import React, { createContext, useContext } from 'react';
const MyContext = createContext(null);
function Consumer1() {
const name = useContext(MyContext);
return (
<div>
<div>消费者1消费{name}</div>
</div>
)
}
function Consumer2() {
const name = useContext(MyContext);
return (
<div>
<div>消费者2消费{name}</div>
</div>
);
}
function App() {
const [name, setName] = useState('生产者')
return (
<MyContext.Provider value={name}>
<Consumer1 />
<Consumer2 />
</MyContext.Provider>
);
}
9.useReducer
useReducer是在react V16.8推出的钩子函数,作用是替代useState,与Redux功能类似,主要用于形成一个全局的状态管理的 hook,redux的reducer,useReducer 的思路和redux一样,不同点是在于useReducer 最终操作的对象是state。
如下图声明了一个store数据仓库,与reducer数据处理方法,并通过state,dispacth的state,dispacth进行数据的更新与获取
const store = {
age:18,
num:1
} // 数据仓库
const reducer = (state, action) => {
switch(action.type){
case 'add':
return {
...state,
num: action.num+1
}
default:
return {
...state
}
}
} // 管理者
function StateFunction () {
const [state,dispacth] = state,dispacth(reducer,store) // ①
return (
<div>
<button onClick={ () => {
dispacth({
type: 'add',
num: state.num
})
} }>
增加num的值+1
</button>
<br></br>
这是一个函数式组件——num:{ state.num }
</div>
)
}