React-Hooks-04-自定义hook的四个典型使用场景

简单的例子,简单计数器实现,抽离业务逻辑成为hook:

function useCounter() {
    const [count, setCount] = useState(0)
    
    const increment = useCallback(() => {
        setCount(count + 1)
    }, [count])
    
    const decrement = useCallback(() => {
        setCount(count - 1)
    }, [count])
    
    const reset = useCallback(() => {
        setCount(0)
    }, [count])
    
    return { count, increment, decrement, reset }
}

在组件中使用这个hook:

function Counter() {
    const { count, increment, decrement, reset } = useCounter()
    return (
        <div>
            <p>{ count }</p>
            <button onClick={decrement}>-</button>
            <button onClick={increment}>+</button>
            <button onClick={reset}>reset</button>
        </div>
    )
}

和高阶组件相比,更加简单

  • 三个典型业务场景

  • 封装通用逻辑:useAsync

    • 如:发起异步请求获取数据并显示在界面上

处理这类请求时,模式都是类似的,通常遵循下面的步骤:

  1. 创建data、loading、error这3个state

  2. 请求发出后,设置loading state为true

  3. 请求成功后,将返回的数据放到某个state中,并将loading state设为false

  4. 请求失败后,设置error state为true,并将loading state设为false

最后,基于state、loading、error这三个state数据,UI就可以正确显示数据了

将逻辑抽离出来:

const useAsync = (asyncFunction) => {
    // 设置3个异步逻辑相关的state
    const [data, setDate] = useState(null)
    cosnt [loading, setLoading] = useState(false)
    const [error, setError] = useState(null)
    // 定义一个callback用于执行异步逻辑
    const execute = useCallback(() => {
        setLoading(true)
        setData(null)
        setError(null)
        return asyncFunction()
            .then((response) => {
                setData(response)
                setLoading(false)
            })
            .catch((erro) => {
                setError(erro)
                setLoading(false)
            })
    }, [asyncFunction])
    
    return { execute, loading, data, error }
}

在组件中使用:

function UserList() {
    const {
        execute: fetchUsers,
        data: users,
        loading,
        error
    } => useAsync(async() => {
        const res = await fetch("http://req/api/users/")
        const json = await res.json()
        return json.data // response
    })
    return (
        // UI...
    )
}
  • 监听浏览器状态:useScroll

    • 界面需要根据在窗口大小变化重新布局

    • 在页面滚动时,需要根据滚动条位置,来决定是否显示一个“返回顶部”的按钮

对应到这个场景就是:

    -组件需要绑定到当前滚动条的位置数据上

const getPosition = () => {
    return {
        x: document.body.scrollLeft,
        y: document.body.scrollTop
    }
}

const useScroll = () => {
    const [position, setPosition] = useState(getPosition())
    useEffect(() => {
        const handler = () => {
            setPosition(getPosition())
        }
        document.addEventListener("scroll", handler)
        return () => {
            document.removeEventListener("scroll", handler)
        }
    }, [])
    return position
}

使用,是否展示返回顶部:

function ScrollTop {
    const { y } = useScroll()
    const goTop = useCallback(()=> {
        document.body.scrollTop = 0
    }, [])
    
    // y会根据scroll动态改变
    if ( y > 300 ) {
        return (
            <button onClick={goTop}>
                Back to Top
            </button>
        )
    }
    return null
}

上一篇:关于图片懒加载的尝试


下一篇:10HUI - 按钮(hui-button)