【React初接触】(四)useRef 和 自定义hook

906 阅读2分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

useRef

返回一个可变的ref 对象,其 .current 属性,被初始化为传入参数。返回的 ref 对象在整个生命周期内保持不变。

const valueRef = useRef(initialValue)

对比createRef :实现点击按钮,input被选中

import { useRef } from 'react';

export default {
    const inputRef = useRef(null)
    const handleFocusInput= () => {
        inputElement.current.focus();
    }

    return (
        <>
            <input ref={inputRef} type="text"/>
            <button onClick={handleFocusInput}>Focus input</button>
        </>
    )
}
import { createRef } from 'react';

export default (props: any) => {
    const inputElement = createRef<HTMLDivElement>();
    const handleFocusInput = () => {
        inputElement.current.focus();
    }
    return (
        <>
            <input ref={inputElement} type="text"/>
            <button onClick={handleFocusInput}>Focus input</button>
        </>
    );
}

createRef每次渲染都会返回一个新的引用,useRef每次都会返回相同的引用。

这一篇文章写的很好: # 什么是 useRef , useRef 与 createRef 区别, 以及在什么情况下使用 useRef, 以及这一篇讲了关于 useRef的“跨渲染周期”保存数据

【实操】

import { useState, useRef } from 'react';
import { Form, Button, Modal } from 'antd';
import type { FormInstance } from 'antd/lib/form';

export default {
    const inputRef = useRef<Input | null>(null);
    const formRef = React.createRef<FormInstance>();
    const [visible, setVisible] = useState(false)

    return (
        <>
            <Button ref={inputRef} onClick={() => setVisible(true)}></Button>
            <Modal
                visible={visible}
                onOk={() => formRef.current?.submit()}
                onCancel={() => setVisible(false)}
            >
                <Form ref={formRef}/>
            </Modal>
        </>
    )
}

自定义hook

用于提取两个函数的共享逻辑。实际上是一个函数,名称use开头,函数内部可以调用其他hook。

两个组件中使用相同的hook不会共享state。 自定义hook是一种重用 状态逻辑 的机制,所以每次使用时,其中的 state 和 副作用都是完全隔离的。

import { useState, useEffect } from 'react'

export default {
    function useFriendStatus(friendId) {
  	const [isOnline, setIsOnline] = useState(null)
    
        useEffect(() => {
            function handleStatusChange(status) {
                    setIsOnline(status.isOnline)
            }

            ChatAPI.subscribeToFriendStatus(friendId, handleStatusChange)
            return () => {
                    ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
            }
        })
  
  	return isOnline
    }
}

// ----  使用 ----- 
function FriendListItem(props) {
  	const isOnline = useFriendStatus(props.friend.id)
    
    return (
    		<li style={{color: isOnline ? 'green' : 'black'}}>
      			{{props.friend.name}}
      	</li>
    )
}

function FriendStatus(props) {
  	const isOnline = useFriendStatus(props.friend.id)
    
    if (isOnline === null) {
      	return 'loading...'
    }
  
  	return isOnline ? 'Online' : 'Offline'
}

hook 规则

  1. 在最顶层使用hook 不要在循环、条件或者嵌套函数中使用
  2. 只在 React函数 中调用 hook
useEffect(() => {
  	// 判断放在useEffect内部
  	if (name !== '') {
      	localStorage.setItem('formDate', name)
    }
})

多个hook传递信息

const friendList = [
  	id: 1, name: 'AAA',
  	id: 2, name: 'BBB', 
  	id: 3, name: 'CCC'
]

function ChatReceiptPicker() {
  	const [receiptId, setReceiptId] = useState(1)
    // 2. 将新的 ReceiptId 传入,获得新的在线情况
  	const isReceiptOnline = useFriendStatus(receiptId)
    return (
        <>
            <Circle color={isReceiptOnline ? 'green' : 'red'}/>
            // 1. 每次更改获得更改后的数据,通过 setReceipt 更新 receiptId
            <select value={receiptId} onChange={e => setReceiptId(Number(e.target.value))}>
                {friendList.map(friend => (
                    <option key={friend.id} value={friend.id}>{friend.name}</option> 
                ))}  
            </select>
      	</>
    )
}

其他hook

useContext

const value = useContext(myContext)

接受一个context对象(React.createContext 的 返回值)并返回该context的当前值。当前的 context值 由上层组件中距离当前组件最近的 <MyContext.Provider>value prop 决定。

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a,b), [a,b])

返回一个 memoized 值

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅在某个依赖项发生变化时重新计算返回值。避免在每次渲染时都进行高开销的计算。

useMemo和useEffect的区别:

useMemo中只执行与渲染有关的操作,而useEffect中执行副作用这类的操作。