Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-hook浅谈 #297

Open
cg669 opened this issue Nov 22, 2019 · 0 comments
Open

react-hook浅谈 #297

cg669 opened this issue Nov 22, 2019 · 0 comments

Comments

@cg669
Copy link

cg669 commented Nov 22, 2019

很久之前react面试都会问道class组件跟function组件有什么区别,很多人都会首先讲到,function组件没有生命周期函数,没有state。

当然由于这两个特别重要的特性,导致了react使用者使用的最多的还是class组件,但是这与作者或者设计者的思想还是有点出入,官方是很推荐使用function组件的。

经过官方不懈努力,以及突发奇想的妙计,在16.8.0版本以后,我们终于可以使用hook了。(hook官方介绍)

具体的api,本人建议还是直接去查阅,首先要通读每一个,搞清楚每一个的使用场景,然后实际项目时候,刚开始还是要仔细阅读一遍。

原因如下:

    1、第一次仔细通篇阅读,理解意思,这样将来项目中遇到某个场景的时候,知道是有这个api的,不会自己只用那几个自己懂的。

    2、百炼锤金,没看一次,也许收获会不一样。

    3、官方文档几乎交代了常用的应用场景。

为什么我会一发不可收拾的爱上hook?

首先,除了给与function组件一些神奇的react特性以外,我们还会发现,在以往的class组件,很多包含自己的状态,然后随之产生的逻辑,几乎难以复用,高阶组件以及render props的解决方案,又会使代码难以理解,以及后期维护成本的增加。

那么hook就有这么神奇的魔力么?是的!

我们可以自定义很多通用的逻辑,然后当成自定义hook。

1、例如:我想实现一个hook,可以满足,用来判断一个元素是否被hover

import { useState, useRef } from 'react'
export function useHover() {
const [value, setValue] = useState(false)

const ref = useRef(null)

const handleMouseOver = () => setValue(true)
const handleMouseOut = () => setValue(false)

useEffect(
() => {
const node = ref.current
if (node) {
node.addEventListener("mouseover", handleMouseOver)
node.addEventListener("mouseout", handleMouseOut)

    return () => {
      node.removeEventListener("mouseover", handleMouseOver)
      node.removeEventListener("mouseout", handleMouseOut)
    }
  }
},
[] // Recall only if ref changes

)

return [ref, value]
}
这样,当我们要对任意函数式组件里某个元素hover状态监听时,只要引用useHover,将返回的ref挂到要监听的元素上,就能实时获取到当前组件的hover状态。

2、又或者我们像对一系列可能同级,可能跨级的组件,都想使用同一个方法,或者组件。以前我们会第一个想到context,或者挂到顶层prop,无限传。

hook可以有个超能力。来个demo

const visibleContext = createContext()

function useProviderVisible() {
const [visible, setVisible] = useState(false)

const [list, setList] = useState(null)

const close = () => {
setList(null)
setVisible(false)
}

return {
visible,
setVisible,
close
}
}

export function VisibleProvider({ children }) {
const viVal = useProviderVisible()
return (
<visibleContext.Provider value={viVal}>{children}</visibleContext.Provider>
)
}

export function useVisible() {
return useContext(visibleContext)
}
这样在我们就有了个visible是否显示的小壳子,哪里需要包哪里,我们还暴露出了,想给外部用户得到的方法跟状态。是不是超棒!

3、useRef组合也很棒,hook本身的api并不是很神奇,重要的是发现他们的深处,组合他们,会发现一个完美而又神奇的新世界!冲鸭!

贴几个常用的:

export function useWindowSize() {
const isClient = typeof window === "object"

const getSize = useCallback(() => {
return {
width: isClient ? window.innerWidth : undefined,
height: isClient ? window.innerHeight : undefined
}
}, [isClient])

const [windowSize, setWindowSize] = useState(getSize)

useEffect(() => {
if (!isClient) {
return false
}

function handleResize() {
  setWindowSize(getSize())
}

window.addEventListener("resize", handleResize)
return () => window.removeEventListener("resize", handleResize)

}, [getSize, isClient]) // Empty array ensures that effect is only run on mount and unmount

return windowSize
}
export function usePrevious(value) {

const ref = useRef()

useEffect(() => {
ref.current = value
}, [value]) // Only re-run if value changes

return ref.current
}

// 倒计时
export default function useCountDown() {
const ref = useRef();
const [num, setNum] = useState(0);
const stop = () => {
if (ref.current) {
clearTimeout(ref.current);
}
};
const start = targetNum => {
setNum(targetNum);
};
const reStart = targetNum => {
if (ref.current) {
clearTimeout(ref.current);
setNum(targetNum);
}
};
const reset = () => {
if (ref.current) {
clearTimeout(ref.current);
setNum(0);
}
};
useEffect(() => {
if (num > 0) {
const newNum = num - 1
const iTimer = setTimeout(() => setNum(newNum), 1000);
ref.current = iTimer;
}
return () => {
if (ref.current) {
clearTimeout(ref.current);
}
};
}, [num]);
return {
stop,
start,
reStart,
reset,
isRunning: num > 0,
num
};
}
const FormContext = createContext(null)

function useFormProvider() {
const [telForm, setTelForm] = useState(null)
const [psdForm, setPsdForm] = useState(null)
const [state, setState] = useState('tel')
return { telForm, setTelForm, psdForm, setPsdForm, state, setState }
}

export function useForm() {
return useContext(FormContext)
}

export function FormProvider({ children }) {
const formValues = useFormProvider()
return <FormContext.Provider value={formValues}>{children}</FormContext.Provider>
}

嘿嘿,还有好多,不贴了,自己去组合吧!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant