react-hook学习
hooks技术不是一门新的技术,而是一种设计思想。
自定义hooks更像是一种约定,而不是一种功能,一般以use开头的,并调用其他hook,就可以称为自定义Hooks(自定义的Hook中,最里面一定是使用了useEffect函数)。
注意:
每次调用 setSate的类似函数(例如:setCount),都会从新执行整个函数组件。
useState()
const [count, setCount] = useState(0);
/*
初始化一个状态变量并带有初始值(0)
count:初始化的状态变量
setCount:改变这个状态的函数(类似与setState())
*/
useContext()
在类组件中有constructor函数,可以用来接收pops属性的值。
但是函数式组件中没有constructor函数,也就没有了接受props属性的地方,那么在这种情况下父组件想向子组件传值就有问题了,为了解决这个问题,引入了useContext()函数。
作用:
-
实现跨越组件层级传递变量,提供全局共享。
useContext()解决组件之间传递的问题。与useReducer()配合使用,可以实现类似于redux的功能。redux整个应用中统一状态管理。 -
context是对它所包含的组件树提供全局共享数据的一种技术。
cont [state, dispatch] = useContext(context)
/*
useContext(context)
接收一个context参数,这个context是由React.createContext(defaultValue)所创建的
*/
const {Provider, Consumer} = context = React.createContext(defaultValue);
function Parent(){
const [count, setCount] = useState(0);
return(
<>
<div>{count}</div>
<button onClick={()=>{setCount(count+1)}}>Click Me</button>
<Provider value={count}>
<Child />
</Provider>
</>
)
}
function Child(){
const count = useContext(context);
return (<h2>{count}</h2>)
}
/*
既然是解决父组件想子组件传值的问题的,那么父组件是如何向子组传递值的呢?
1. 父组件需要把将要传递的值放到context中
2. 子组件使用useContext()获取父组件传递的值
//定义一个父组件最外层的context变量(可以单独成文件,然后再父组件和子组件中分别引入使用)
const {Provider, Consumer} = context = React.createContext(defaultValue);
Provider是传值方(context.Providert)
Consumer是接收方(context.Consumer)
function Parent(){
const [count, setCount] = useState(0);
return(
<>
<div>{count}</div>
<button onClick={()=>{setCount(count+1)}}>Click Me</button>
//将父组件要传递的值放入到context中
<Provider value={count}>
//这样父组件中的count发生变化后,子组件的值就会发生改变
<Child />
</Provider>
</>
)
}
//重点 重点 重点
function Child(){
//使用useContext()接收父组件传递过来的属性值,这里useContext会获取到离子组件最近的父组件传递过来的值
//同时需要注意的是,这里的context必须要与父组件是相同的context,才可以实现数据的共享。
const count = useContext(context);
return (<h2>{count}</h2>)
}
*/
useEffect(func,[deps])
相当于类组件中的componentDidMount()、componentDidUpdate()以及componentWillUnmount()的合并,即完成DOM修改后的调用函数
func:表示DOM渲染后需要执行的函数体。
deps:表示这个useEffect()的依赖项,依赖项发生改变,就会再次执行func函数体。
useEffect()如果函数中由需要清除的副作用,就需要在useEffect()函数体内返回一个函数
useEffect(()=>{
//....
return ()=>{
//需要清除的副作用
}
},[])
useReducer(reducer,initState)
useReducer(reducer,initState)用来管理state状态(多个状态需要同时修改时,建议使用:例如:登录验证)
import React,{useReducer} from 'react'
export default function ReducerDemo() {
const [count, dispath] = useReducer((state,action)=> {
switch(action){
case 'add':
return state + 1;
case 'sub':
return state - 1;
default:
return state;
}
}, 0);
return (
<div>
<h1 className="title">{count}</h1>
<button className="btn is-primary"
onClick={()=> dispath('add')}
>Increment</button>
<button className="btn is-warnning"
onClick={()=> dispath('sub')}
>Decrement</button>
</div>
)
}
/*
const [count, dispatch] = useReducer(reducer,initState)
reducer: 一个负责改变state的值的函数,
这个函数由两个参数:reducer(state,action)
state:初始状态
action:reducer函数会根据action的类型来判断将怎么改变这个state
count:状态改变后的值
dispatch:一个触发reducer的机制,在组件中调用。(重要)
return [
...state,
{
id:10,
name:"haha"
}
]
这句话的意思是,先copy一个state,然后修改这个state
*/
useRef(initValue)
const like = useRef(0);
//贯穿组件的整个生命周期,组件重新渲染后like的值不会改变,保持原值。
useLayoutEffect(func,[deps])
布局副作用:
useEffect在浏览器渲染完成后执行
useLayoutEffect在浏览器渲染完成前执行
特点:
useLayoutEffect总是比useEffect先执行
useLayoutEffect里面的任务最好影响layout(布局)
注意:
最好是使用useEffect(为了用户体验最好)
useCallback(func,[deps])
解决:函数组件的每一次调用都会执行其内部的所有逻辑,那么会带来较大的性能损耗。
useMemo()和useCallback()就是解决这些问题的杀手锏。
- useMemo() 返回缓存的变量
- useCallback() 返回缓存的函数
const funA = useCallback(funcB, [deps]);
//将传递进来的funcB返回给funcA,并且将这个结果进行缓存,如果依赖改变了,就会返回新的函数。
注意:
useMemo(),useCallback(),useEffect()都是自带闭包的,即组件每次重新渲染,其都会捕获当前组件函数上下文中的状态(stat,props),所以它反映的也都是组件当前的状态。
useMemo(initValue)
类似与useCallback,只是useMemo返回的是缓存的变量。
const valueA = useMemo(2);
//valueA变量会一直保留,重新渲染组件时不会重新定义这个变量。
浙公网安备 33010602011771号