React之5 编程式函数Hook
Hook解决函数组件不能使用state的问题。函数式组件比class组件好用,这时候hook它来了,这样函数式组件也能使用state,岂不是爽歪歪。
5.1 新特性useState(组件状态管理钩⼦)
用法:
const [state,setState]=useState(initState)
state是要设置的状态
setState是更新state的⽅法,只是⼀个⽅法名,可以随意更改
initState是初始的state,可以是随意的数据类型,也可以是回调函数,但是函数必须是有返回值
App.js
使用Hook前
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
count:0
}
Add(){
this.setState(
{
count:this.state.count+1
}
)
}
render() {
return (
<div>
<div>你点击了{this.state.count}</div>
<button onClick={()=>this.Add()}>点击</button>
</div>
)
}
}
使用Hook后(是不是感觉简洁了很多^^)
import React, { useState } from 'react'
const App = () => {
const [count, setCount] = useState(0)
return (
<div>
<div>你点击了{count}</div>
<button onClick={() => setCount(count + 1)}>点击</button>
</div>
)
}
export default App
5.2 新特性useEffect(副作⽤处理钩⼦)
⼀般称数据获取、订阅、定时执⾏任务、⼿动修改ReactDOM这些⾏为都可以称为副作⽤
useEffect也是componentDidMount、componentDidUpdate和componentWillUnmount这⼏个⽣命周期⽅法的统⼀
用法
useEffect(callback,array)
callback: 回调函数,作⽤是处理副作⽤逻辑
callback可以返回⼀个函数,⽤作清理
useEffect(() =>{
//副作⽤逻辑 xxxxxx
return ()=>{
//清理副作⽤需要清理的内容
//类似于componentWillUnmount,组件渲染和组件卸载前执⾏的代码
}
},[])
array(可选参数):数组,⽤于控制useEffect的执⾏
数组分三种情况:
空数组,则只会执⾏⼀次(即初次渲染render),相当于componentDidMount
⾮空数组,useEffect会在数组发⽣改变后执⾏
不填array这个数组,useEffect每次渲染都会执⾏
import React, { useState, useEffect } from 'react'
const App = () => {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `点击次数${count}`
return () => {
console.log('组件更新或卸载')
}
},[count])
return (
<div>
<div>你点击了{count}</div>
<button onClick={() => setCount(count + 1)}>点击</button>
</div>
)
}
export default App
5.3 新特性useContext
⼀般会使⽤第三⽅状态管理器来实现全局数据共享
redux
dva
mobx
useContext(context)是针对context上下⽂提出的⼀个Hooks提出的⼀个API,它接受React.createContext()的返回值作为参数,即context对象,并返回最近的context
使⽤useContext是不需要再使⽤Provider和Consumer的
当最近的context更新时,那么使⽤该context的hook将会重新渲染
使用context:
import React, { Component } from ‘react’
//创建上下文
const HahaContext=React.createContext()
const {Provider,Consumer}=HahaContext
let store={
name:'uncleHuang',
sex:'女'
}
class Info extends Component{
render(){
return(
<Consumer>
{
store=>{
return(
<div>
<p>姓名:{store.name}</p>
<p>性别:{store.sex}</p>
</div>
)
}
}
</Consumer>
)
}
}
function ToolBar(props){
return(
<div>
<Info></Info>
</div>
)
}
class App extends Component {
render() {
return (
<div>
<h1>高阶组件上下文通信</h1>
<Provider value={store}>
<ToolBar></ToolBar>
</Provider>
</div>
)
}
}
export default App
使用useContext:
import React, { useContext } from 'react'
const Context=React.createContext({name:'uncleHuang',sex:'female'})
const App = () => {
const value = useContext(Context)
return (
<div>
<div>姓名:{value.name}</div>
</div>
)
}
export default App
5.4 新特性useReducer
useReducer是useState的⼀个增强体,可以⽤于处理复杂的状态管理
useReducer可以完全替代useState,只是我们简单的状态管理⽤ useState⽐较易⽤,useReducer的设计灵感源⾃于redux的reducer
对⽐⼀下useState和useReducer的使⽤:
//useState的使⽤⽅法
const [state,setState]=useState(initState)
//useReducer的使⽤⽅法
const [state,dispatch]=useReducer(reducer,initState,initAction)
reducer是⼀个函数,根据action状态处理并更新state
initState是初始化的state
initAction是useReducer初次执⾏时被处理的action
state状态值
dispatch是更新state的⽅法,他接受action作为参数
useReducer只需要调⽤dispatch(action)⽅法传⼊action即可更新state,使⽤如下
//dispatch是⽤来更新state的,当dispatch被调⽤的时候,reducer⽅法也会被调⽤,同时根据action的传⼊内容去更新state
action是传⼊的⼀个描述操作的对象
dispatch({type:'add'})
reducer是redux的产物,他是⼀个函数,主要⽤于处理action,然后返回最新的state,可以把reducer理解成是action和state的转换器,他会根据action的描述去更新state,使⽤例⼦:
(state,action) => Newstate
import React, { useReducer } from 'react'
const initState={count:0}
const reducer=(state,action)=>{
switch(action.type){
case 'reset':
return initState;
case 'add':
return {count:state.count+1};
case 'reduce':
return {count:state.count-1};
default:
return state
}
}
const App = () => {
const [state, dispatch] = useReducer(reducer, initState)
return (
<div>
<p>当前数量是:{state.count}</p>
<div><button onClick={()=>dispatch({type:'reset'})}>重置</button></div>
<div><button onClick={()=>dispatch({type:'add'})}>加一</button></div>
<div><button onClick={()=>dispatch({type:'reduce'})}>减一</button></div>
</div>
)
}
export default App
useContext可以解决组件间的数据共享问题,⽽useReducer可以解决复杂状态管理的问题,如果把他们结合起来使⽤,就可以实现redux的功能了,意味着未来我们可以不再依赖第三⽅状态管理器了
5.5 官⽹介绍额外的Hooks
1、useMemo ⽤于性能优化,通过记忆值来避免在每个渲染上执⾏⾼开销的计算
适⽤于复杂的计算场景,例如复杂的列表渲染,对象深拷⻉等场景
使⽤⽅法如下
const memoValue =useMemo(callback,array)
callback是⼀个函数⽤于处理逻辑
array 控制useMemo重新执⾏的数组,array改变时才会 重新执⾏useMemo
useMemo的返回值是⼀个记忆值,是callback的返回值
不能在useMemo⾥⾯写副作⽤逻辑处理,副作⽤的逻辑处理放在useEffect内进⾏处理
import React, { useMemo } from 'react'
const obj1={name:'小驴',sex:'男',age:'12'}
const obj2={name:'小马',sex:'女',age:'13',like:'和小驴同学一起玩'}
const App = () => {
const memoValue=useMemo(() => Object.assign(obj1,obj2), [obj1,obj2])
return (
<div>
<div>姓名:{memoValue.name}----年龄:{memoValue.age}</div>
</div>
)
}
export default App
2、UseCallback和useMemo⼀样,也是⽤于性能优化的
基本使⽤⽅法
const memoCallback= useCallback(callback,array)
callback是⼀个函数⽤于处理逻辑
array 控制useCallback重新执⾏的数组,array改变时才 会重新执⾏useCallback
跟useMemo不⼀样的是返回值是callback本身,⽽useMemo返回的是callback函数的返回值
const obj1 = { name: '小驴', sex: '男', age: '12' }
const obj2 = { name: '小马', sex: '女', age: '13', like: '和小驴同学一起玩' }
const App = () => {
const memoCallBackValue = useCallback(() => Object.assign(obj1, obj2), [
obj1,
obj2
])
return (
<div>
<div>
姓名:{memoCallBackValue().name}----年龄:{memoCallBackValue().age}
</div>
</div>
)
}
export default App
3、useRef ⽅便我们访问操作dom
import React, { useRef } from 'react'
const App = () => {
//创建ref
const ref = useRef()
const getValue=()=>{
// 访问ref
console.log(ref.current.value)
}
return (
<div>
<input ref={ref} type="text"></input>
<button onClick={getValue}>获取input值</button>
</div>
)
}
export default App
5.6 封装自定义Hooks
import React, { useEffect } from 'react'
//封装的Hooks⽤use开头
const useChangeTitle = title => {
useEffect(() => {
document.title = title
}, [title])
}
export default props => {
useChangeTitle('自定义修改标题Hooks')
return <div>测试自定义Hooks</div>
}
5.7 React Hooks的使⽤规则
只在顶层调⽤Hooks
Hooks的调⽤尽量只在顶层作⽤域进⾏调⽤不要在循环,条件或者是嵌套函数中调⽤Hook,否则可能会⽆法确保每次组件渲染时都以相同的顺序调⽤Hook
只在函数组件调⽤Hooks
React Hooks⽬前只⽀持函数组件,所以别在class组件或者普通的函数⾥⾯调⽤Hook钩⼦函数
React Hooks的应⽤场景如下
函数组件
⾃定义hooks