React Hooks
介绍
1.1 React Hooks 是用来做什么的
对函数型组件进行增强, 让函数型组件可以存储状态, 可以拥有处理副作用的能力.让开发者在不使用类组件的情况下, 实现相同的功能.
2.1 useState
- 接收唯一的参数即状态初始值. 初始值可以是任意数据类型.
- 返回值为数组. 数组中存储状态值和更改状态值的方法. 方法名称约定以set开头, 后面加上状态名称.
- 方法可以被调用多次. 用以保存不同状态值.
- 参数可以是一个函数, 函数返回什么, 初始状态就是什么, 函数只会被调用一次, 用在初始值是动态值的情况.
useState 设置状态值
- useState() 设置状态值方法的参数可以是一个值也可以是一个函数
- 设置状态值方法的方法本身是异步的
import { useState } from 'react'
function App (props) {
const [count, setCount] = useState(() => {
// 初始执行一次
return props.count || 0
})
const [person, setPerson] = useState({
name: 'zhang',
age: 10
})
function handleCount () {
setCount(count => {
const newCount = count + 1
document.title = newCount
return newCount
})
}
return (
<div className="App">
<p>{count}</p>
<p>{person.name}</p>
<p>{person.age}</p>
<button onClick={handleCount}> +1 </button>
<button onClick={() => setPerson({ name: 'ss', age: 0 })}>setPerson</button>
</div>
);
}
2.2 useReducer
useReducer是另一种让函数组件保存状态的方式.
function reducer (state, action) {
switch (action.type) {
case 'increment':
return state + 1
case 'decrement':
return state - 1
default:
break;
}
}
const [useReducerCount, dispatch] = useReducer(reducer, 0)
<div>
<p>useReducer</p>
<p>{useReducerCount}</p>
<button onClick={() => dispatch({ type: 'increment' })}>useReducerCount + 1</button>
<button onClick={() => dispatch({ type: 'decrement' })}>useReducerCount - 1</button>
</div>
2.3 useContext
useContext()在跨组件层级获取数据时简化获取数据的代码.
// 组件
function Foo () {
// 简化
const fooCount = useContext(countContext)
return <div>
{fooCount}
</div>
}
<div>
<countContext.Provider value={100}>
<Foo />
</countContext.Provider>
</div>
2.4 useEffect()
2.4.1 useEffect() 执行时机
让函数型组件拥有处理副作用的能力. 类似生命周期函数.
- useEffect 执行时机可以把 useEffect 看做 componentDidMount, componentDidUpdate 和 componentWillUnmount 这三个函数的组合.
- useEffect(() => {}) => componentDidMount, componentDidUpdate
- useEffect(() => {},[]) => componentDidMount
- useEffect(() => () => {}) => componentWillUnMount
2.4.2 useEffect 解决的问题
- 按照用途将代码进行分类 (将一组相干的业务逻辑归置到了同一个副作用函数中)
- 简化重复代码, 使组件内部代码更加清晰
2.4.3 useEffect 结合异步函数
useEffect(() => {
// 自执行函数
(async function () {
let res = await getData()
console.log(res)
})()
}, [])
function getData () {
return new Promise((resolve, reject) => {
resolve({ msg: 'Hello' })
})
}
2.4.4.指定数据变化触发 useEffect
useEffect(() => {
console.log('sss')
document.title = count
}, [count])
2.5 useMemo()
- useMemo 的行为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值.
- useMemo 会缓存计算结果. 如果监测值没有发生变化, 即使组件重新渲染, 也不会重新计算. 此行为可以有助于避免在每个渲染上进行昂贵的计算.
const [useMemoCount, setUseMemoCount] = useState(0)
function handlerSetUseMemoCount () {
setUseMemoCount(useMemoCount => {
return useMemoCount + 1
})
}
const double = useMemo(() => {
console.log('1')
return useMemoCount * 2
}, [useMemoCount])
<div>
<p> useMemo </p>
<p> {useMemoCount} {double}</p>
<p>{bool ? '真' : '假'}</p>
<button onClick={handlerSetUseMemoCount}>handlerSetUseMemoCount</button>
<button onClick={() => setBool(!bool)}>setBool</button>
</div>
2.6 memo ⽅法 性能优化, 如果本组件中的数据没有发⽣变化, 阻⽌组件更新
2.7 useCallback 性能优化, 缓存函数, 使组件重新渲染时得到相同的函数实例
// 不会重新渲染
const resetCount = useCallback(() =>
setCount(0), [setCount]
)
<div>
<p>Zoo</p>
useCallback 防止点击 resetCount Zoo组件重新渲染
<Zoo resetCount={resetCount} />
</div>
const Zoo = memo(function Zoo (props) {
console.log('重新渲染')
return <div>
我是zOO
<button onClick={props.resetCount}>resetCount</button>
</div>
})
2.8 useRef()
获取DOM元素对
const useName = useRef()
function handler () {
console.log(useName, 'useName')
}
<div>
<p>useRef</p>
<input ref={useName} onChange={handler}></input>
</div>
保存数据 (跨组件周期) 即使组件重新渲染, 保存的数据仍然还在. 保存的数据被更改不会触发组件重新渲染
const UseRef = memo(function UseRef () {
const [count, setCount] = useState(0)
let timerId = useRef()
useEffect(() => {
timerId.current = setInterval(() => {
setCount(count => count + 1)
}, 1000)
}, [])
const stopCount = () => {
console.log(timerId)
clearInterval(timerId.current)
}
return <div>
我是useRef
<div>{count}</div>
<button onClick={stopCount}>停止</button>
</div>
})
3. 自定义 HOOK 不共享
- ⾃定义 Hook 是标准的封装和共享逻辑的⽅式.
- ⾃定义 Hook 是⼀个函数, 其名称以 开头.
- ⾃定义 Hook 其实就是逻辑和内置 Hook 的组合
// 自定义hooks
function useGetPost () {
const [post, setPost] = useState({})
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/posts/1')
.then(res => {
setPost(res.data)
})
}, [])
return [post, setPost]
}
const Hooks = memo(function Hooks (params) {
const [post] = useGetPost()
return <div>
Hooks
<div>{post.title}</div>
<div>{post.body}</div>
</div>
})
function useUpdateInput (initialValue) {
const [value, setValue] = useState(initialValue)
return {
value,
onChange: event => setValue(event.target.value)
}
}
const From = memo(function From (params) {
const usernameInput = useUpdateInput('')
const passwordInput = useUpdateInput('')
const submitForm = event => {
event.preventDefault();
console.log(usernameInput.value, passwordInput.value)
}
return <div>
<form onSubmit={submitForm}>
<input type="text" name="username" {...usernameInput} />
<input type="password" name="password" {...passwordInput} />
<input type="submit" />
</form>
</div>
})