React Hooks 使用

Hooks 是一项新功能提案,可以在不编写类的情况下使用 state(状态)和其他 react 功能

使用 hooks 的理由

  • 高阶组件为了复用,会导致代码层级复杂
  • 类声明的组件中,生命周期复杂,代码编写容易混乱
  • 写成函数式组件,是无状态组件;因为需要状态,又得改成 class 组件,开发成本变高

hooks 的使用

  • useState() 保存组件状态

    /* 
    	语法:const [state, setstate] = useState(initState),可以定义多个状态
    		state:状态名
    		setstate:改变对应状态的方法
    		initState:状态的初始值
    */
    import React, { useState } from 'react'
    
    export default function App (props) {
        const [stateA, setstateA] = useState(true)
        
        return (
        	<div>
                状态:{ stateA }
                <button onClick = { ()=> setstateA(false) }>修改状态</button>
            </div>
        )
    }
    
  • useRef() 保存引用值

    import React, { useRef } from 'react'
    
    export default function App (props) {
    	/**
    		创建ref的方式有两种:
    			const ref1 = createRef()
    			const ref2 = useRef()
    			在第初始化阶段,使用 createRef 与 useRef 两者是没有区别。但是在第更新阶段两者是有区别的。
    			1. 我们使用一个外部的变量store来存储初次所创建的ref,在我们对组件进行更新后,更新后的ref与我们初次创建的ref其实并不一致。这样也就意味着我们每更新一次组件, 就重新创建一次ref。
    			2. 使用 useRef 创建的 ref 仿佛就像外部定义的一个全局变量,不会随着组件的更新而重新创建。但组件销毁,它也会消失,不用手动进行销毁。
    	*/
        cosnt myInput = useRef('')
        
        return (
        	<div>
                input 的 value值:{ myInput.current.target.value }
                <input type='text' ref={ myInput } />
            </div>
        )
    }
    
  • useCallback() 记忆函数

    • 防止因为组件重新渲染,而导致方法被重新创建,起到缓存作用,只有第二个参数发生改变才会重新声明一次函数
    /*
    	语法:let handleClick = useCallback(fn, [依赖项])
    		第一个参数事件处理函数
    		第二个参数:依赖项,数组形式
    			1. 如果第二个参数不传,每次数据更新都会重新声明这个函数
    			2. 如果第二个参数传入空数组,那么函数中的数据就会被缓存,
    			   即使数据改变,函数中的永远的原来的数据
                3. 如果第二个参数传入对应依赖项,只有依赖项改变后,这个函数才会重新声明一次
    */
    import React, { useState, useCallback } from 'react'
    
    export default function App (props) {
        const [name, setname] = useState('小明')
        
        let handleClick = useCallback(() => { // 只有 name 改变,才会重新声明这个函数
            console.log(name)
        }, [name])
        
        return (
        	<div>
                <button onClick = { handleClick }>click</button>
            </div>
        )
    }
    
  • useEffect() 处理副作用 和 useLayoutEffect() 同步执行副作用

    • 函数式组件中不存在生命周期,而使用上述方法可以处理对应的业务逻辑
    • 如果明明使用某个变量,却没有申明在依赖中,当依赖改变时,useEffect 也不会再执行了,且 eslint 会报警告
    • useLayoutEffect 与 useEffect 用法一样,区别是一个同步执行,一个异步执行
    /*
    	语法:useEffect(fn, [依赖项])
    		第一个参数事件处理函数
    			注意:该参数如果返回一个回调函数,则这个回调函数会在该组件即将销毁时调用:可以用来做事件解绑、清除定时器操作
    		第二个参数:依赖项,数组形式
    			1. 如果第二个参数不传,每次数据更新都会重新执行这个函数
    			2. 如果第二个参数传入空数组,那么这个函数只有在初始化的时候执行一次
                3. 如果第二个参数传入对应依赖项,那么初始化和依赖项改变时都会执行这个函数
    */
    import React, { useState, useEffect } from 'react'
    import axios from 'axios'
    
    export default function App (props) {
        const [list, setlist] = useState([])
        
        const id = props.match.params.id
        useEffect(() => {
            axios.get(`http://loaclhost:5000/user/${id}`).then(res => {
                setlist(res.data)
            })
        }, [id])
        
        return (
        	<div>
                <p>app</p>
            </div>
        )
    }
    

    区别:useLayoutEffect 是同步执行的,会在 dom 更新完成后立即执行,但是会在浏览器进行热歌绘制之前运行完成,阻塞了浏览器的绘制,跟 class 写法的 componentDidMount 和 componentDidUpdata 类似,都是同步执行

    useEffect 是异步执行的,不会阻塞浏览器绘制,性能会更好一点

  • useReducer 和 useContext 减少组件层级

    • 全局状态
    import React, { useReducer} from 'react'
    
    // 利用 context 状态树全局通信
    const GlobalContext = React.createContext()
    
    // reducer 可以抽离出去
    const reducer = (prevState, action) => {
        const newState = {...prevState}
        
        switch(action.type) {
            case 'set_isShow' :
                newState.isShow = action.payload
                return newState
                
            default :
                return prevState
        }
    }
    
    export default function App () {
        const [state, dispatch] = useReducer(reducer, {isShow: ture})
        
        return (
            // 把 state, dispatch 传给所有子组件
            <GlobalContext.Provider value = {{state, dispatch}}>
                <div>
                    { state.isShow }
                </div>
            </GlobalContext.Provider>
        )
    }
    
    • 子组件中接收
    import React, { useContext } from 'react'
    
    export default function Son () {
        // 通过 useContext 获取根组件传递的数据
        const {state, dispatch} = useContext.(GlobalContext)
        return (
        	<div>
            	{ state.isShow }
            </div>
        )
    }
    

    自定义 hooks

    • 当我们想在两个函数之间共享逻辑,或者想抽离出组件内的 hooks 时,我们可以把它们提到单独的函数中
    • 自定义 hooks 的函数名必须是以 use 开头 ,否则会报错
    import React, { useState, useEffect } from 'react'
    import axios from 'axios'
    
    // 自定义的 hooks
    function useGetList (id) {
        const [list, setlist] = useState([])
        
        useEffect(() => {
            axios.get(`http://loaclhost:5000/user/${id}`).then(res => {
                setlist(res.data)
            })
        }, [id])
        
        return list
    }
    
    export default function App (props) {
        const id = props.match.params.id
        const list = useGetList(id)
         
        return (
        	<div>
                <p>app</p>
            </div>
        )
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值