hook 是16.8新增的特性,他能让你在不使用class 组件的情况下也能用class组件的特性
下面就来简单讲讲几个常用的api吧
API:
首先我们通过React 引入对应的API
import React, { useState } from 'react'
useState()
相当于创建一个state ,创建规则
const [ a, setA ] = useState(); //创建一个state对象
第一个 a 表示存储数据的参数,第二个setA 表示当要改变这个值时要执行的函数相当于 this.setState(),useState()里面可以传入一个函数,返回值为当前默认值:
const [ a, setA ] = useState(()=>1); //a的默认值为1
useEffect() 模拟class 的生命周期
第一个参数为函数
const useEffect(()=>{
//相当于componentDidMount()和componentDidUpdata()
console.log("componentDidMount执行了....");
console.log("componentDidUpdata执行了....");
},[]);
传入的函数返回一个函数 ,返回的函数相当于 componentWillUnmount()
const useEffect(()=>{
//相当于componentDidMount()和componentDidUpdata()
console.log("componentDidMount执行了....");
console.log("componentDidUpdata执行了....");
return ()=>{
//执行销毁任务时触发
console.log("componentWillUnmount执行了....");
}
},[]);
第二个参数为一个数组,
当数组没有值时默认全部useState的变量都触发第一个参数的函数
//当数组中传入特定的useState设置的值时,
//只有当遇到与之相对应的值变化时才开启执行第一个参数函数
const useEffect(()=>{
//相当于componentDidMount()和componentDidUpdata()
console.log("a被改变了....更新dom ");
return ()=>{
//执行销毁任务时触发
console.log("componentWillUnmount执行了....");
}
},[a]);//a不改变就不执行更新
利用这个特性我们可以过滤掉没有发生改变的state值不更新dom
useRef() 相当于 class 的 ref
let ref=useRef();// 创建ref
return (
{/*给dom元素赋值ref,这样我们就能获取ref */}
<div ref={ref}>页面<div/>
)
//我们可以通过ref.current的值获取当前元素
我们可以通过useRef第一次的加载没有值的特性过滤掉第一次useEffect()的执行
let ref=useRef();// 创建ref
const useEffect(()=>{
if(!ref.current){//如果没有值,是第一次执行 ,直接过滤
console.log('执行了componentDidWillmount.....')
ref.current=true;
}
//相当于componentDidMount()和componentDidUpdata()
console.log("执行了componentDidUpdata..... ");
return ()=>{
//执行销毁任务时触发
console.log("componentWillUnmount执行了....");
}
});
我们通过useEffect()来模拟class的生命周期
const [a, setA] = useState('a');
const [b, setB] = useState('b');
//16.8之后新增。useRef是hook的功能
useEffect(() => {
console.log('componentDidMount.....');
}, []);
useEffect(() => {
return ()=>{
console.log('componentWillUnMount.....');
}
}, []);
const didmount = useRef();
useEffect(()=>{
if(!didmount.current)
return;
console.log('a didUpdate.........');
}, [a]);
useEffect(()=>{
if(!didmount.current)
return;
console.log('b didUpdate.........');
}, [b]);
useEffect(() => {
// 过滤第一次挂载
if(!didmount.current){
didmount.current = true;
return;
}
console.log('componentDidUpdate.........');
});
return (
<div>
<h1>two组件</h1>
<button onClick={()=>setA('aa')}>{a}</button>
<button onClick={()=>setB('bb')}>{b}</button>
</div>
)
useCallback()
参数第一个为一个回调(钩子)函数
const btnAction = useCallback(()=>{
/* 我们可以通过回调函数传入子组件做一些事情 */
console.log('执行了回调函数...')
})
return (
<div>
<Button btnAction={btnAction} />/* 将回调函数传入组件, */
</div>
)
useCallback包裹的函数,组件初始化时,创建一次,
之后的每一次更新,都获得上一次函数,不会重新声明函数
但是组件内部的依赖发生变化,上一次的函数就会释放,重新声明一个函数,所以如果函数内部触发了state的值的改变,就必须传入相应的值
const [a,setA]=useState('a');
const [b,setB]=useState('b');
const btnAction = useCallback(()=>{
console.log('执行了回调函数...')
/* 使用了b的值,所以b值被缓存下来,
如果下一次在调用,用的还是原来的b,
如果b在外部发生了变化,则需要重新给新的b值 */
setA(b)
},[b])
return (
<div>
<Button btnAction={btnAction} />/* 将回调函数传入组件, */
</div>
)
memo() 相当于class 的 PureComponent 过滤,没有改变的值就不刷新
有两个参数:
第一个参为一个组件,
第二个参数相当于 class的shoudComponentupdata()
第一个参数为组件
const Button = memo(( ) => {
return (
<div>
< button>按钮</button >
</div>
)
})
export default Button
或者
function Button() {
return (
<div>
<button>按钮</button >
</div>
)
}
export default memo(Button)
第二个参数 可以省略不写
const Button = memo((props) => {
return (
<div>
< button>按钮</button >
</div>
)
},
(oldProps, newProps) => {
//接收两个参数,第一个是旧的props 第二个是新的props
console.log(oldProps, newProps)
//第二个函数表示 class 的should ComponentDidupdata()
//自定义memo false 表示一定更新
//如果为true 表示不更新。和class 的相反
return true
}
)
useMemo()
组件内部的数据变化优化,没有触发改变的state数据就不重新执行计算代码
应用场景:首页轮播图请求一次之后,其他数据需要改变,会导致轮播图数据请求触发,我们可以通过useMemo()来过滤轮播图的数据请求代码
const [a, setA] = useState(56)
const [b, setB] = useState(44)
const [show, setShow] = useState(false)
console.log('组件渲染执行了');
const btnAction = useCallback(() => {
setShow(true)
}, [])
const result = useMemo(() => {
//求最大公约数
var result = 1;
for (var i = 1; i <= a && i <= b; i++) {
console.log('进入了');
if (a % i === 0 && b % i === 0) {
result = i;
}
}
return result
}, [a, b])//如果依赖没有变化,就不更新,如果依赖发生改变,就重新计算
return (
<div>
<p>{a}</p>
<p>{b}</p>
<p>最大公约数{result}</p>
<button onClick={btnAction}>按钮</button>
{show && <div
style={{ width: '100px',
height: '100px',
background: 'red' }}>
</div>}
</div>
)
useContext() 将Context简化使用
简洁使用 context 获取数据
import React, { Component ,useContext} from 'react'
import BorderContext from '../context/BorderContext'
import ColorContext from '../context/ColorContext'
//之前的使用
// export default class Box extends Component {
// render() {
// return (
// <BorderContext.Consumer >
// {(border) => {
// console.log(border);
// return (
// <ColorContext.Consumer>
// {(color) => {
// return (<div style={{ border: border, color: color, width: '100px', height: '100px' }}>ewwe</div>)
// }}
// </ColorContext.Consumer>
// )
// }}
// </BorderContext.Consumer>
// )
// }
// }
// useContext()的使用
import React, { Component, useContext } from 'react'
import BorderContext from '../context/BorderContext'
import ColorContext from '../context/ColorContext'
export default function Box(params) {
const border = useContext(BorderContext)//获取所有的值
const color = useContext(ColorContext) //获取所有的值
return (<div style={{ border: border, color: color, width: '100px', height: '100px' }}>ewwe</div>)
}
路由新增hook Api 简化使用history location match
import { useHistory, useLocation, useRouteMatch, useParams } from "react-router-dom"
export default function One(props) {
const inputDOM = useRef();
console.log(props);
const history = useHistory();
const location = useLocation();
const match = useRouteMatch();
const params = useParams();
console.log(history, location, match, params)
return (
<div>
<h1>one页面</h1>
<input type="text" ref={inputDOM} />
<button onClick={() => {
if (inputDOM.current.value.length > 0) {
//跳转页面
props.history.push('/detail');
} else {
alert('输入不能为空');
}
}}>按钮</button>
</div>
)
}
这些是我学习hook时留下的一些笔记,如果有错误,还望大神们指出!谢谢
具体内容请观看官网文档:
https://react.docschina.org/docs/hooks-intro.html