背景
Hooks 是React 16.8中的新增功能。它們允許您在不編寫class的情況下使用狀態和其他React功能,關於原理性東西其他大佬已經說很多了,我今天主要講實踐具體用法。
關於recompose --- 高階元件 hoc 庫
作者自己寫很推崇 hooks
翻譯過來就是基本api
官方連結傳送門
常用api:
- useState
- useEffect
- useReducer
- useRef
- useContext
常用 api
useState
const [storeCustomerBaseInfo, updateStoreCustomerBaseInfo] = useState({})
複製程式碼
陣列第一個值是你需要更新的值,第二個值是更新該值得函式 useState() 函式執行的時候給預設值 我這裡是給的空物件 具體更新栗子如下
if (res.success) {
const { storeCustomerBaseInfo, storeUserPayInfo } = res.data
updateStoreCustomerBaseInfo(storeCustomerBaseInfo)
}
複製程式碼
useEffect
通俗點就是 componentDidMount,componentDidUpdate、componentWillUnmount三個生命週期的合集,
複製程式碼
一般在這裡發起非同步請求?
useEffect(() => {
getWebData(id)
}, [id])
const getWebData = async (id) => {
const res = await CustomerService.getCustomerDeatil(id)
if (res.success) {
const { storeCustomerBaseInfo, storeUserPayInfo } = res.data
updateStoreCustomerBaseInfo(storeCustomerBaseInfo)
}
}
複製程式碼
細心的同學會發現我在函式末尾多加了個引數 這裡相當於我類似於 didMount 方法,如果不加該引數,就會一直請求。 預設情況下,它在第一次渲染之後和每次更新之後執行,你可能會發現更容易認為效果發生在“渲染之後”,而不是考慮“掛載”和“更新”React保證DOM在執行‘效果’時已更新。 加引數就相當於自定義更新,比如我這裡加了 id 只有當id 重新變化的時候再執行該方法
如何做一些取消操作呢?
比如定時器,釋出訂閱,有時候元件解除安裝的時候要取消這個時候該怎麼辦呢
解決辦法
return 一個新的函式
useEffect(() => {
fecth()
return () => {
clearTimeOut()
}
})
複製程式碼
useReducer
useState的替代方案。接受型別為(state,action) => newState的reducer,並返回與dispatch方法配對的當前狀態。 (如果熟悉Redux,你已經知道它是如何工作的。) 用過 redux的相信對這個reducer 都不陌生 使用和redux 如出一撤
//actions.js
export const showMsg = 'SHOW_MSG'
export const openpoolInfo = 'OPENPOOL_INFO'
export const updateShowMsg = (data) => ({
type: showMsg,
data
})
export const updateOpenpoolInfo = (data) => ({
type: openpoolInfo,
data
})
複製程式碼
- reducer 部分
import {
showMsg,
openpoolInfo
} from './actions'
export const initState = {
showMsg: true,
openpoolInfo: {}
}
export const initReducer = (state, action) => {
switch (action.type) {
case showMsg:
return {
...state,
showMsg: action.data
}
case openpoolInfo:
return {
...state,
openpoolInfo: action.data
}
default:
return state
}
}
複製程式碼
最後連結元件
import React, { useEffect, useReducer } from 'react'
import { Page } from '../../components'
import { Divider, Button, message } from 'antd'
import { CustomerService } from '../../service'
import BaseInfo from './base_info'
import Edit from './edit'
import { yuan2Fen, fen2Yuan } from '../../helper'
import { updateShowMsg, updateEditTotalOpenPoolAmount, updateOpenpoolInfo } from './store/actions'
import { initState, initReducer } from './store/reducer'
const OpenPool = (props) => {
const [state, dispatch] = useReducer(initReducer, initState)
const { params: {id} } = props.match
useEffect(() => {
getOpenpoolInfo(id)
}, [id])
const getOpenpoolInfo = async (id) => {
const res = await CustomerService.getOpenpool(id)
if (res.success) {
dispatch(updateOpenpoolInfo(res.data))
}
}
const editChange = (editTotalOpenPoolAmount) => {
const { usedOpenPollAmount } = state.openpoolInfo
const showMsg = fen2Yuan(usedOpenPollAmount) - editTotalOpenPoolAmount > 0
dispatch(updateShowMsg(showMsg))
dispatch(updateEditTotalOpenPoolAmount(editTotalOpenPoolAmount))
}
const getParms = () => {
const { usedOpenPollAmount } = state.openpoolInfo
return {
customerId: id,
usedOpenPollAmount,
totalOpenPoolAmount: yuan2Fen(state.editTotalOpenPoolAmount)
}
}
const updateAmount = async () => {
const params = getParms()
const res = await CustomerService.updateOpenpool(params)
if (res.data) {
message.success('操作成功')
}
}
return (
<Page title='xxx'>
<BaseInfo {...state.openpoolInfo} />
<Divider />
<Edit
showMsg={state.showMsg}
{...state.openpoolInfo}
editTotalOpenPoolAmount={state.editTotalOpenPoolAmount}
editChange={editChange}
/>
</Page>
)
}
export default OpenPool
複製程式碼
TS 的用法
其實和上面的沒太大變化只要設定型別就行了,當然你也可以不設定
import { Button } from 'antd'
import * as React from "react";
const { useState } = React
const Home = () => {
const [count, setCount] = useState(0)
const [strings, setStrings] = useState<string[]>([])
return (<div>
<Button onClick={() => setCount(1)}>測試普通型別</Button>
<Button onClick={() => setStrings([])}>測試檢測型別</Button>
</div>)
}
export default Home
複製程式碼
再來看看使用 interface
import { Button } from 'antd'
import * as React from "react";
const { useState } = React
interface IType {
counts: number;
}
const About = () => {
const [counts, setCount] = useState<IType[]>([]);
return (<div>
<Button onClick={() => setCount([{counts: 1}])}>測試普通型別</Button>
<Button onClick={() => setCount([]}>測試普通型別</Button>
</div>)
}
export default About
複製程式碼
注意在某些 tslint 版本里面 定義interface 一定要用 Ixxx 開頭不然會一直爆紅 具體請看issue
彩蛋
以上是我個人的實踐,現在估計看完都會有疑問到底是用 useState 還是 useReducer, 看了國外某大神的文章你就明白了 傳送門