React Hooks 是⽤来做什么的
- 对函数型组件进⾏增强, 让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒
- 让开发者在不使⽤类组件的情况下, 实现相同的功能.
类组件的不足
-
缺少逻辑复⽤机制
为了复⽤逻辑增加⽆实际渲染效果的组件,增加了组件层级 显示⼗分臃肿
增加了调试的难度以及运⾏效率的降低
-
类组件经常会变得很复杂难以维护
将⼀组相⼲的业务逻辑拆分到了多个⽣命周期函数中
在⼀个⽣命周期函数内存在多个不相⼲的业务逻辑
-
类成员方法不能保证this指向的正确性
Hooks使用
Hooks 意为钩⼦, React Hooks 就是⼀堆钩⼦函数, React 通过这些钩⼦函数对函数型组件进⾏增强, 不同的钩⼦函数提供了不同的功能.
钩子函数
-
useState()
用于为函数组引入状态
import React, { useState } from 'react' function App(props) { const [count, setCount] =useState(()=>{ return props.count || 0; }) const [ person, setPerson]=useState({name: '张三', age: 20}) return ( <div> <span>{count} {person.name} {person.age}</span> <button onClick={()=>{setCount(count+1)}}>+</button> <button onClick={()=>{setPerson({...person,name: '李四'})}}> 修改</button> </div> ); } export default App;
-
接收唯⼀的参数即状态初始值. 初始值可以是任意数据类型
-
返回值为数组. 数组中存储状态值和更改状态值的⽅法. ⽅法名称约定以set开头, 后⾯加上状态名称
-
⽅法可以被调⽤多次. ⽤以保存不同状态值
-
参数可以是⼀个函数, 函数返回什么, 初始状态就是什么, 函数只会被调⽤⼀次, ⽤在初始值是动态值的情况.
-
-
useEffects()
设置状态值方法的参数可以是一个值也可以是一个函数
设置状态值方法的方法本身是异步的
-
useReducer()
userReducer是另一种让函数组件保存的方式
import React, { useReducer } from 'react' function App() { function reducer(state, action){ switch (action.type) { case 'increment': return state + 1; case 'decrement': return state - 1; default: return state; } } const [ count, dispatch ]=useReducer(reducer,0) return ( // setcount <div> <button onClick={() => dispatch({type: 'increment'})}>+</button> <span>{count}</span> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </div> ); } export default App;
-
useRef()
- 获取DOM元素对象
import React, { useRef } from 'react'; function App() { const box = useRef(); return <div ref={box}> <button onClick={()=>{ console.log(box)}}>获取div</button> </div> } export default App;
-
保存数据(跨组件周期)
- 即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染
import React, { useState, useEffect, useRef } from 'react'; function App() { const [count, setCount] = useState(0); let timeId = useRef(); useEffect(()=>{ timeId.current = setInterval(()=>{ setCount(count => count + 1) }, 1000) }, []) const stopCount = () =>{ console.log(timeId) clearInterval(timeId.current) } return <div> <span>{count}</span> <button onClick={stopCount}>stop</button> </div> } export default App;
-
useCallback()
性能优化,缓存函数,使组件重新渲染时得到相同的函数实例
import React, { useState, memo, useCallback } from 'react'; function App() { const [count,setCount] = useState(0); const resetCount= useCallback(()=>setCount(0),[setCount]) return <div> <span>{count}</span> <button onClick={() => setCount(count + 1) }>+</button> <Foo resetCount={resetCount}/> </div> } // 避免重新渲染 const Foo = memo(function Foo (props) { console.log('Foo组件重新渲染') return <div> 我是Foo组件 <button onClick={props.resetCount}>resetCount</button> </div> }) export default App;
-
useContext()
在跨组件层级获取数据时简化获取数据的代码
import React, { createContext, useContext } from 'react' const countContext = createContext(); function App() { return <countContext.Provider value={100}> <Foo /> </countContext.Provider>; } function Foo () { // 简化获取数据时的代码 const value = useContext(countContext) // 以前的写法 // return <countContext.Consumer> // { // value =>{ // return <div>{value}</div> // } // } // </countContext.Consumer> return <div>我的测试数据{value}</div> } export default App;
-
useMemo()
-
useMemo 的⾏为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值
-
useMemo 会缓存计算结果. 如果监测值没有发⽣变化, 即使组件重新渲染, 也不会重新计算. 此⾏为可以有助于避免在每个渲染上进⾏昂贵的计算.
-
-
useEffect()
一、让函数组件拥有处理副作用的能力、类似生命周期函数
-
useEffect 执⾏时机
可以把 useEffect 看做 componentDidMount, componentDidUpdate 和 componentWillUnmount 这三个函数的组合.
useEffect(() => {}) => componentDidMount, componentDidUpdate
useEffect(() => {}, []) => componentDidMount
useEffect(() => () => {}) => componentWillUnMount
import React, { useState, useEffect } from 'react' import ReactDom from 'react-dom' function App() { const [count, setCount] = useState(0); // 组件挂载完成之后执行 组件数据更新完成之后执行 // useEffect(() => { // console.log(1) // }) // 组件挂载完成之后执行 // useEffect(()=>{ // console.log(123) // },[]) // 组件被卸载之前执行 useEffect(()=>{ return () =>{ console.log('组件被卸载了') } }) return <div> <span>{count}</span> <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => ReactDom.unmountComponentAtNode(document.getElementById('root'))}>卸载组件</button> </div>; } // function useEffectApp() { // return <div>ssssss</div> // } export default App;
二、useEffect使用方法
-
为window对象添加滚动事件
-
设置定时器让count数值每隔⼀秒增加
import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom' function App() { function onScroll () { console.log('页面发生滚动了') } useEffect(() => { window.addEventListener('scroll', onScroll) return () =>{ window.removeEventListener('scroll', onScroll) } }, []) const [count,setCount] = useState(0); useEffect(()=>{ const timeId = setInterval(()=> { setCount(count=>{ document.title = count + 1; return count +1 }) },1000) return () =>{ clearInterval(timeId) } }, []) return <div> <span>{count}</span> <button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>卸载组件</button> </div> } export default App;
三、useEffect 解决的问题
- 按照⽤途将代码进⾏分类 (将⼀组相⼲的业务逻辑归置到了同⼀个副作⽤函数中)
- 简化重复代码, 使组件内部代码更加清晰
四、只有指定数据发⽣变化时触发effect
useEffect(() => { document.title = count }, [count])
五. useEffect 结合异步函数
useEffect中的参数函数不能是异步函数, 因为useEffect函数要返回清理资源的函数, 如果是异步函数就变成了返回Promise
useEffect(() => { (async function() { let response = await getData(); console.log(response) })()
-
-
-
memo方法
性能优化, 如果本组件中的数据没有发⽣变化, 阻⽌组件更新. 类似类组件中的 PureComponent 和 shouldComponentUpdate
import React, { useState, memo } from 'react'; function App() { const [count,setCount] = useState(0); return <div> <span>{count}</span> <button onClick={() => setCount(count + 1) }>+</button> <Foo /> </div> } // 避免重新渲染 const Foo = memo(function Foo () { console.log('Foo组件重新渲染') return <div>我是Foo组件</div> }) export default App;
自定义Hook
-
⾃定义 Hook 是标准的封装和共享逻辑的⽅式
-
⾃定义 Hook 是⼀个函数, 其名称以 use 开头
-
⾃定义 Hook 其实就是逻辑和内置 Hook 的组合.
自定义hook需要安装axios库
import React, { useEffect, useState } from 'react';
import axios from 'axios'
// 自定义hook
function useGetPost () {
const [post,setPost] = useState(0);
useEffect(()=>{
axios.get('http://janet.show:1337/posts/1')
.then(response => setPost(response.data))
}, [])
return [post, setPost]
}
function App() {
const [post, setPost] = useGetPost()
return <div>
<div>{post.title}</div>
<div>{post.content}</div>
</div>
}
export default App;
React路由Hooks
React-router-dom 路由提供的钩子函数
import React from 'react';
import { useHistory, useLocation, useRouteMatch, useParams} from 'react-router-dom'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkT8Ms1w-1613552571335)(images/image-20210215225523356.png)]