1、简介
2、state hooks
import React, {useState} from "react";
function ClickHooks() {
// useState就是一个'钩',最基本的一个 Hook
const [name, setName] = useState('Lisa')
// 等价于
// const arr = useState(0)
// const name = arr[0]
// const useName = arr[1]
const handleClick = () => {
setName(name + '2020')
}
return <div>
<h1>{name}</h1>
<button onClick={handleClick}>点击</button>
</div>
}
export default ClickHooks
总结
hooks 命名规范
3、Effect hooks
import React, {useState, useEffect} from "react";
function LifeCircles() {
const [name, setName] = useState('Lisa')
const [count, setCount] = useState(0)
const handleClick = () => {
setName(name + '2020')
setCount(count + 1)
}
// 模拟class 组件的 didMount 和 didUpdate 生命周期
// useEffect(() => {
// console.log('发送了一个ajax请求')
// }) // 没有第二个参数
// 只模拟 DidMount 生命周期
useEffect(() => {
console.log('加载了')
}, []) // 第二个参数为 [],不依赖任何 state
// 只模拟 DidUpdate 生命周期
useEffect(() => {
console.log('更新了')
}, [count, name]) // 第二个参数为依赖的 state
// 模拟 class 组件的 willUnMount
useEffect(() => {
const timer = window.setInterval(() => {
console.log('11111111')
}, 200000)
// 返回一个函数,模拟class 组件的 willUnMount
return () => {
window.clearInterval(timer)
}
}, []) // 第二个参数为依赖的 state
return <div>
<h1>{name}</h1>
<h1>{count}</h1>
<button onClick={handleClick}>点击</button>
</div>
}
export default LifeCircles
模拟willUnMount,但不完全相等
4、其他hooks
useRef
import React, {useEffect, useRef} from "react";
function LifeCircles() {
const btnRef = useRef(null)
useEffect(() => {
console.log(btnRef.current) // Dom 节点
})
return <div>
<button ref={btnRef}>点击</button>
</div>
}
export default LifeCircles
useContext
import React, {useContext} from "react";
const themes = {
light: {
background: '#ccc'
},
dark: {
background: '#000',
color: '#ccc'
}
}
// 创建context
const ThemeContext = React.createContext(themes.light)
function ThemeButton() {
const theme = useContext(ThemeContext)
return <button style={{background: theme.background, color: theme.color}}>hello world</button>
}
function ToolBar() {
return <ThemeButton></ThemeButton>
}
function UseContextDemo() {
return <div>
<ThemeContext.Provider value={themes.dark}>
<ToolBar></ToolBar>
</ThemeContext.Provider>
</div>
}
export default UseContextDemo
useReducer
import React, {useReducer} from "react";
const initialState = {count: 0}
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 UseReducerDemo() {
const [state, dispatch] = useReducer(reducer, initialState)
return <div>
count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</div>
}
export default UseReducerDemo
useMemo
import React, {useState, memo, useMemo} from "react";
// 子组件
// function Person({info}) {
// console.log('child mount')
// return <div>
// <h1>{info.name}</h1>
// <h1>{info.age}</h1>
// </div>
// }
// 类似 class PureComponent,对 props进行浅比较
const Person = memo(({info}) => {
console.log('child mount')
return <div>
<h1>{info.name}</h1>
<h1>{info.age}</h1>
</div>
})
function UseMemoDemo() {
console.log('parent mount')
const [count, setCount] = useState(0)
const [name, setName] = useState('Lisa')
const [age, setAge] = useState(20)
// const person = {name, age}
// 用 useMemo 缓存数据,有依赖
const person = useMemo(() => {
return {name, age}
}, [name, age])
return <div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>Add</button>
<Person info={person}></Person>
</div>
}
export default UseMemoDemo
useCallback
import React, {useState, memo, useMemo, useCallback} from "react";
// 类似 class PureComponent,对 props进行浅比较
const Person = memo(({info, handleChange}) => {
console.log('child mount')
return <div>
<input type="text" onChange={handleChange}/>
<h1>{info.name}</h1>
<h1>{info.age}</h1>
</div>
})
function UseCallBackDemo() {
console.log('parent mount')
const [count, setCount] = useState(0)
const [name, setName] = useState('Lisa')
const [age, setAge] = useState(20)
// const person = {name, age}
// 用 useMemo 缓存数据,有依赖
const person = useMemo(() => {
return {name, age}
}, [name, age])
// const handleChange = (e) => {
// console.log(e.target.value)
// }
const handleChange = useCallback((e) => {
console.log(e.target.value)
}, [])
return <div>
<h2>{count}</h2>
<button onClick={() => setCount(count + 1)}>Add</button>
<Person info={person} handleChange={handleChange}></Person>
</div>
}
export default UseCallBackDemo
5、自定义hooks
6、 规范和注意事项
错误示范:
7、hooks 依赖于调用顺序
8、class 组件逻辑复用有哪些问题 ?
9、Hooks 组件逻辑复用有哪些好处 ?
// react hooks 实现逻辑复用
import React, {useEffect, useState} from "react";
function useMousePosition() {
const [x, setX] = useState(0)
const [y, setY] = useState(0)
useEffect(() => {
function getMousePosition(event) {
setX(event.clientX)
setY(event.clientY)
}
document.body.addEventListener('mousemove', getMousePosition)
return () => document.body.removeEventListener('mousemove', getMousePosition)
}, [])
return [x, y]
}
export default useMousePosition
import useMousePosition from './view/useMousePosition'
function App() {
const [x, y] = useMousePosition()
return <div className="App">
<div style={{width: '100%', height: '200px', backgroundColor: '#ccc'}}>
<h1>鼠标位置:{x} - {y}</h1>
</div>
</div>
}
export default App;
10、hooks 使用中的几个注意事项 ?
代码演示坑一:
代码演示坑二:
依赖为 [] 的时候,re-render 不会重新执行 effect 函数; 没有依赖,re-render 会重新执行 effect 函数
代码演示坑三:
如果
useEffect中的依赖为数组或者是对象的话,可能会出现死循环,原因是底层使用objece.is()进行比较依赖是否变化
针对坑二,可以使用 useRef解决