1、Hook 是什么
官方介绍:Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
2、Hook 的Api
- 1、
useState
设置类组件中的state
import React, { useState } from "react";
// useState: 可以在函数式组件中声明和修改状态
//函数式组件
function App() {
//使用hook来定义state
//获得state,和修改state的函数。
const [value, setValue] = useState("123");
如果初始值比较复杂,可以用一个函数包裹,返回一个复杂对象。
const [userInfo, setUserInfo] = useState(getUserInfo);
//如果需要定义多个状态,就调用多次useState
return (
<div>
<p>value: {value}</p>
<input type="text" value={value} onChange={onChangeAction} />
<input type="text" value={value} onChange={onChangeAction()} />
// 这里加不加括号结果 都是一样的。应该在内部做了判断吧。
</div>
)
// 输入框的修改事件
const onChangeAction = (ev) => {
//调用上面定义的修改函数,要返回一个新的state,保证state的属性是不可变量。
setValue(ev.target.value);
};
const getUserInfo = ()=>{
return {
a:1,
b:2
}
}
}
export default App
- 2、
useEffect
用来模拟 类组件中的各种生命周期钩子函数
//解构出`effect` // useEffect: 需要有一组依赖的state,如果依赖的state发生变化, 那么回调就会执行。
import React, { useState, useEffect } from "react";
... //下面是函数组件内部代码
const [value, setValue] = useState("123");
// effect
// 只要组件的所有state/props发生变化就执行。以及初始化也会执行
useEffect(()=>{
console.log('1 useEffect run.......');
});
// 如果第二个参数提供了数组,数组中只能是state的值或者props的值
// 只有依赖发生变化,回来哦函数才执行。并且判断是否发生变化,比较的是状态的引用。
useEffect(()=>{
console.log('2 useEffect run.......');
}, [value, props.data]);
// 如果第二个参数为空数组,那么第一个回调就相当于class组件的componentDidMount
useEffect(()=>{
console.log('3 useEffect run.......');
//而且在effect函数中是可以拿到DOM对象的
}, []);
useEffect(()=>{
console.log('4 useEffect run.......');
console.log(document.querySelector('#flag').innerHTML);
// 返回的函数,会在下一次渲染完组件后,执行下一次的useEffect前,先调用上一次返回的useEffect返回的函数。
return (...rest)=>{
console.log('4 useEffect return func run.......');
console.log(document.querySelector('#flag').innerHTML);
}
});
useEffect(()=>{
console.log('5 useEffect run.......');
return ()=>{
// 当依赖为空时,useEffect返回的函数,相当于class组件的componentWillUnmount
console.log('5 useEffect return func run.......');
}
}, []);
//暂时Hook 只能模拟这几个钩子函数
- 3、
useRef
用来拿到DOM对象,类组件中的 React.createRef 一样。
import React, { useRef } from 'react'
... //下面是函数组件内部代码
let h4DOM = useRef();
return (
//用法和类组件中一样,都是从current中取值。
<h4 ref={h4DOM}>test</h4>
// console.log(h4DOM.current);
)
- 4、
useContext
提供数据的用法和类组件是一样的,不同点在于消费数据。
//初始化仓库数据,可以用useState,同时提供数据和修改数据的方法。
const [value, setValue] = useState(1)
<DataContext.Provider
value={{
value,
setValue,
//将属性和修改属性的方法,一起存在仓库中
}}
>
<div className="app">
<One />
<hr />
<Two />
</div>
</DataContext.Provider>
//调用的时候
import React, {useContext} from 'react'
import DataContext from '../context/DataContext'
import ThemeContext from '../context/ThemeContext'
export default function Two() {
const context = useContext(DataContext);
console.log(context);
const context2 = useContext(ThemeContext);
console.log(context2);
return (
<div>
<h1>{context.value}</h1>
<button onClick={()=>{
context.setValue(context.value+1);
}}>修改</button>
</div>
)
}
- 5、
useCallback
该hook,保证了某一些特殊函数,只执行一次,避免过多执行而消耗性能,第一个参数是想只执行一次的函数体,第二个参数可以是函数体用到的依赖状态。
import React, { useEffect, useState, useCallback } from 'react'
const list = [];
export default function App() {
console.log('render.....');
const [value, setValue] = useState('');
// useCallback作用:声明一次函数,当组件再次渲染,取上次渲染时声明的函数直接使用。
// 但是,当依赖发生变化时,又会重新声明一次函数。
// 如果在组件中定义局部的函数,那么就是用useCallback包裹,注意useCallback的依赖一定要正确。
const valueChange = useCallback((ev)=>{
console.log(value);
setValue(ev.target.value);
}, [value]);
useEffect(()=>{
list.push(valueChange);
console.log(list.length);
if(list.length === 2){
console.log(list[0] === list[1]);
}
});
return (
<div className="app">
<h1>value: {value}</h1>
<input type="text" value={value} onChange={valueChange}/>
</div>
)
}
- 6、
useMemo
相当于计算属性,只有依赖的值发生变化,才会执行memo包裹的函数。
import React, { useState, useCallback, useMemo, memo } from "react";
function One() {
console.log("render............");
const [a, setA] = useState(1);
const [b, setB] = useState(2);
const [c, setC] = useState(3);
const list = [];
// useMemo相当于计算属性
// 第一个参数是个函数,需要返回计算的属性,第二个参数是依赖,依赖发生变化,重新计算属性。
const result = useMemo(() => {
// 计算属性的代码
var result = 100;
for (var i = 1; i <= a && i <= b; i++) {
console.log("计算最大公约数...");
if (a % i === 0 && b % i === 0) {
result = i;
}
}
// 计算得到的属性,需要返回出去
return result;
}, [a, b]);
console.log(result);
const btn1Action = useCallback(() => {
setA((a) => a + 1);
}, []);
const btn2Action = useCallback(() => {
setB((b) => b + 1);
}, []);
const btn3Action = useCallback(() => {
setC((c) => c + 1);
}, []);
return (
<div>
<p>A: {a}</p>
<p>b: {b}</p>
<p>求A,B的最大公约数:{result}</p>
<p>c: {c}</p>
<button onClick={btn1Action}>修改A</button>
<button onClick={btn2Action}>修改B</button>
<button onClick={btn3Action}>修改C</button>
</div>
);
}
export default memo(One);
- 7、useHistory 与 useLocation 与 useMatch 用来获取路由参数,相当于类组件中的 withRouter 高阶组件。
import React from "react";
import { useHistory, useLocation ,useRouteMatch ,useParams } from "react-router-dom";
//在类组件中除了 利用 component 属性来跳转的路由,其他都拿不到上面三个属性,需要用到高阶组件 withRouter包裹才能用到。
//利用Hook 就可以直接拿到。但是要是在Router的包裹范围内。
export default function Two(props) {
const history = useHistory();
console.log(history);
const location = useLocation();
console.log(location);
}
- 8 、useSelect 与 useDispatch 与 useStore 用来获取store中的数据和方法。类组件中用到高阶组件 content
import React from 'react'
import { useCallback } from 'react';
import {useSelector, useDispatch, useStore} from 'react-redux'
export default function One(props) {
// 获取redux仓库中的数据
const val = useSelector(state=>{
return state.value;
});
// 获取dispatch
const dispatch = useDispatch();
const btnAction = useCallback(()=>{
dispatch({type: 'modify-value', value: 'hello'});
}, [dispatch]);
// 获得仓库
const store = useStore();
console.log(store);
return (
<div className="one">
<h1>one组件</h1>
<h2>{val}</h2>
<button onClick={btnAction}>修改value</button>
</div>
)
}