react系列-1-hooks
前言
React 16.8 新增了hooks特性,这是一项激动人心的功能,可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
React的组件创建方式,一种是类组件,一种是纯函数组件,并且React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。也就是说组件的最佳写法应该是函数,而不是类。
但目前开发中我们基本都在使用类组件开发,因为纯函数组件有类组件不具备的多种特点,如:
- 纯函数组件没有状态
- 纯函数组件没有生命周期
- 纯函数组件没有this
我们使用类组件实现一个简答的计时器功能:
import React, {Component} from 'react';
class AddCount extends Component {
constructor(props){
super(props)
this.state={
count: 0
}
}
addcount = () => {
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<>
<p>{this.state.count}</p>
<button rimary" onClick={this.addcount}>Add</button>
</>
)
}
}
export default AddCount
可以看到,一个小功能,但看起来却非常“重”,对于类组件,无论业务代码多少,constructor、render等都是必须的。
类组件功能齐全却很重,纯函数很轻便却有上文几点重大限制,为了解决上述问题。React团队设计了React Hooks。
什么是React Hooks
hooks,顾名思义,就是“钩子”的意思,因为函数组件没有状态,所以对于一个全功能的组件,,如果需要外部功能和副作用,就用钩子把外部代码”钩”进来。而React Hooks 就是我们所说的“钩子”。更进一步说,React Hooks就是加强版的函数组件。
我们先将上述类组件改为函数组件:
import React, {useState } from 'react';
const AddCount = () => {
const [count, setCount] = useState(0);
const addcount = () => {
let newCount = count
setCount(newCount+=1)
}
return (
<div>
<p>Count: {count}</p>
<button onClick={addcount}>Add</button>
</div>
);
};
export default AddCount;
可以看到函数组件 + React Hooks的写法更简洁:没有了渲染逻辑,没有了生命周期等。
下面介绍React Hooks的四种默认钩子:
React Hooks的钩子
userState():状态钩子
纯函数组件没有状态,useState()用于为函数组件引入状态
在useState()中,它接受状态的初始值作为参数,即上例中计数的初始值,它返回一个数组:
数组第一项是一个变量,指向状态的当前值。类似this.state
数组第二项是一个函数,用来更新状态,类似setState
useContext():共享状态钩子
依旧从上面例子进行扩展,假设组件A与组件B共享状态:
import React, {useContext,createContext, useState } from 'react';
import { Button } from 'antd-mobile';
const Count=()=>{
const [count,setCount]=useState(0);
const AppContext =createContext({})
const A=()=>{
const { val } = useContext(AppContext)
return(
<p>我是组件A,我接收到的count值为{val}</p>
)
}
const B=()=>{
const { val } = useContext(AppContext)
return(
<p>我是组件A,我接收到的count值为{val}</p>
)
}
return (
<AppContext.Provider value={{val: count}}>
<A></A>
<B></B>
<Button onClick={()=>{setCount(count+1)}}>Add</Button>
</AppContext.Provider>
);
}
export default Count;
运行结果:
useReducer():Action钩子
因为react本身并不提供状态管理的功能,所以一般是通过外部库来解决,最常用到的就是redux。
redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态,
Reducer函数的形式是(state, action) => newstate
。
useReducers()钩子用来引入 Reducer 功能
const [state, dispatch] = useReducer(reducer, initialState)
Reducer 函数和状态的初始值作为参数,返回一个数组:
数组的第一项是状态的当前值
数组的第一项是发送 action 的dispatch函数
我们依旧实现一个计数器:
import React, {useReducer} from 'react';
const AddCount = () => {
const reducer=(state,action)=>{
if(action.type==="add"){
return {
...state,
count:state.count+1
}
}else{
return state
}
}
const addcount=()=>{
dispatch({
type:"add"
})
}
const [state, dispatch] = useReducer(reducer, {count:0})
return(
<div>
<p>Count: {state.count}</p>
<button onClick={addcount}>Add</button>
</div>
)
}
export default AddCount
由于 Hooks 可以提供共享状态和 Reducer 函数,所以它在这些方面可以取代 Redux。但是,它没法提供中间件(middleware)和时间旅行(time travel),如果你需要这两个功能,还是要用 Redux。
useEffect():副作用钩子
useEffect()用来引入具有副作用的操作,最常见的就是向服务器请求数据。以前,放在componentDidMount里面的代码,现在可以放在useEffect()。
import React, {useEffect,useState} from 'react';
const GetList = () => {
const [loading, setLoading] = useState(true);
const [count, setCount] = useState(0);
useEffect(() => {
setLoading(true);
fetch(`https://xxx.xxx.com/InterfaceApi/News/noticeList`)
.then(response => response.json())
.then(data => {
setCount(data.data.count);
setLoading(false);
});
}, [])
if (loading === true) {
return <p>Loading ...</p>
}
return(
<div>
<p>list lens: {count}</p>
</div>
)
}
export default GetList
运行结果:
创建自己的Hooks
react提供给我们了四种默认React Hooks,有时候我们需要创建自己想要的Hooks,来满足更便捷的开发,其实无非就是根据业务场景对以上四种Hooks进行组装,从而得到满足自己需求的钩子,此处不再展开。