Hook是React16.8的新增特性、它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。引入hook有什么意义呢?
1、丰富了函数组件的能力、使其具有状态管理能力;
2、组件逻辑复用,Hook表现的更好【写共用方法一样】,而比class组件的 mixin【废弃了】、HOC、render props更加易懂;
3、class复杂组件正在变的费解、不易拆解、测试,逻辑混乱;
在react中已经内置了一些hook 【useState、useEffect、useMemo、useCallback、useRef、useContext、useReducer】和 可自定义hook。下面一个个分析其用处。
一、useState---函数添加状态、使其实现state 和 setState功能 【重要】
ps:默认函数组件没有state, 且是一个纯函数,执行完即销毁, 无法存储state,需要state Hook, 把state功能 "钩"到纯函数中。
用法:
1、接受一个参数作为初始值
2、返回一个数组、第一个值为状态、第二个值为改变状态的函数
// 数组结构 推荐[name setName]格式; 可见 useState 返回的是一个数组
function StateHookDemo () => {
const [name, setName] = useState('terry')
return <div onClick={() => setName('jerry')}>点击更新</div>
}
export default StateHookDemo
二、useEffect---模拟class组件的生命周期,添加结束渲染的信号【重要】
用法:
1、接受一个函数作为参数
2、接收第二个参数数组[],依赖列表, 只有依赖更新时,才会执行函数, 也可以不传;
function effectHookDemo () => {
const [name, setName] = useState('terry')
// 模拟componentDidMount 和 componentDidUpdate
// 即在初始化会打印 entry ,当点击更新是 也会打印entry
useEffect(() => {
console.log(‘entry’) // 初始化会打印 , 点击更新也会打印
});
// 模拟 componentDidMount
useEffect(() => {
console.log(‘entry’) // 初始化会打印 , 点击更新不会打印
}, []); //第二个参数是空数组
// 模拟 componentDidUpdata
useEffect(() => {
console.log(‘entry’) // 初始化不会打印 , 点击更新会打印
}, [name]); //第二个参数是依赖, 即当name更新了才触发
// 模拟componentWillUnMount
useEffect(() => {
const timer = setIntervel(() => {
console.log(Date.now())
}, 1000)
// 返回一个函数
// 模拟componentWillUnMount
return () => {
clearInterval(timer )
}
}, []);
return <div onClick={() => setName('jerry')}>点击更新</div>
}
export default effectHookDemo
三、useRef---长久保存数据【可用来获取dom】
作用:
1、保存一个值, 在整个生命周期中维持不变
2、重新赋值ref.current不会触发重新渲染
function refHookDemo () => {
const btnRef = useRef(null)
useEffect(() => {
console.log(btnRef.current) // DOM节点
}, [])
return <div>
<button ref={btnRef}>click</button>
</div>
}
export default refHookDemo
四、useContext---带着组件去流浪
用法:
1、需要引入useContext和 createContext
2、通过createContext创建一个context句柄
3、Context.Provider来确定数据共享的范围
4、通过value来分发内容
5、在子组件在中通过useContext(context句柄)来获取数据
// 1、引入useContext和 createContext
import React, { useContext, createContext } from 'react'
// 颜色主题
const themes = {
light: {
background: '#eee'
},
dark: {
background: '#222'
}
}
// 2、通过createContext创建一个context句柄
const ThemeContext = createContext(themes.light) // 初始值
function ThemeButton() {
//5、 在子组件在中通过useContext(context句柄)来获取数据
const theme = useContext(ThemeContext)
return <button style={{ background: theme.background}}>
hello world
</button>
}
function Toolbar() {
return <div>
<ThemeButton></ThemeButton>
</div>
}
function App() {
// 3、Context.Provider来确定数据共享的范围
// 4、通过value来分发内容
return <ThemeContext.Provider value={themes.dark}>
<Toolbar></Toolbar>
</ThemeContext.Provider>
}
export default App
五、useReducer---借鉴redux, 应对复杂的state变化
用法:
1、 数据仓库 store
2、需要管理者 reducer
3、useReducer(reducer, store) 返回一个数组,[state, dispatch]
import React, { useReducer } from 'react'
const store = { count: 0 } // 创建仓库store
//2、需要管理者 reducer
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
default:
return state
}
}
function App() {
// 很像 const [count, setCount] = useState(0)
const [state, dispatch] = useReducer(reducer, store)
return <div>
count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>decrement</button>
</div>
}
export default App
ps: useReducer 和 redux的区别
1、useReducer是useState的代替方案, 用于state的复杂变化
2、useReducer 是单个组件状态管理,组件通信还是要props
3、redux是全局的状态管理, 多组件共享数据
六、useMemo---缓存hook 缓存数据 用于性能优化
用法:
1、 接收一个函数作为参数
2、第二个参数为依赖列表
3、返回一个值
import React, { useState, memo, useMemo } from 'react'
// 类似 class PureComponent ,对 props 进行浅层比较
const Child = memo(({ userInfo }) => {
console.log('Child render...', userInfo) // 不用useMemo的话, 点击click 这个会打印 重新渲染
return <div>
<p>This is Child {userInfo.name} {userInfo.age}</p>
</div>
})
// 父组件
function App() {
console.log('Parent render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('双越老师')
// const userInfo = { name, age: 20 }
// 用 useMemo 缓存数据,有依赖
const userInfo = useMemo(() => {
return { name, age: 21 }
}, [name])
return <div>
<p>
count is {count}
<button onClick={() => setCount(count + 1)}>click</button>
</p>
<Child userInfo={userInfo}></Child>
</div>
}
export default App
七、useCallback---缓存hook 缓存函数 用于性能优化
用法:
1、 接收一个函数作为参数
2、第二个参数为依赖列表
3、返回一个函数
import React, { useState, memo, useMemo, useCallback } from 'react'
// 子组件,memo 相当于 PureComponent
const Child = memo(({ userInfo, onChange }) => {
console.log('Child render...', userInfo) // 看是否会打印
return <div>
<p>This is Child {userInfo.name} {userInfo.age}</p>
<input onChange={onChange}></input>
</div>
})
// 父组件
function App() {
console.log('Parent render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('terry')
// 用 useMemo 缓存数据
const userInfo = useMemo(() => {
return { name, age: 21 }
}, [name])
// function onChange(e) {
// console.log(e.target.value)
// }
// 用 useCallback 缓存函数
const onChange = useCallback(e => {
console.log(e.target.value)
}, [])
return <div>
<p>
count is {count}
<button onClick={() => setCount(count + 1)}>click</button>
</p>
<Child userInfo={userInfo} onChange={onChange}></Child>
</div>
}
export default App