同一组件内部,通过useref来获取某一个dom标签以及dom标签的方法。
在以前使用ref的时候,我们经常用ref来保存某个需要的dom标签,这样需要用到的时候,就可以不用去寻找这个dom标签了,在js中,通过方法,parentNode,lastchild,nextElementsibling 这种关系结构来找dom是一件比较麻烦的事情。如果不是动态类名或者id的话,通过document.getElementsByClassName 之类的方法,虽然可行,却也比较麻烦,因为得到的是一个dom数组。
看看useref如何实现
import React, { useState, useEffect, useMemo, useRef } from 'react';export default function App(props){const [count, setCount] = useState(0);const doubleCount = useMemo(() => {return 2 * count;}, [count]);const couterRef = useRef(); //创建useRefuseEffect(() => {document.title = `The value is ${count}`;//通过couterRef 的current 属性可以获取到button这个domconsole.log(couterRef.current);}, [count]);return (<>//与ref类似,绑定到button标签上<button ref={couterRef} onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button></>);}
跨组件获取子组件的方法。
在以往的ref中,可以将ref绑定到某个子组件标签上,用以获取整个子组件的方法和参数,在react 的useref也有类似的功能。
父组件代码
import React, { useRef } from 'react';import StudentStatusForm from './components/student-status-info-emdit//student-status-info-emdit';const StudentBase: React.FC = (props) => {const onClickConfirmStudentStatusInfo = () => {//获取StudentStatusForm 子组件onFinish方法userInfoStatus.current.onFinish().validateFields().then(() => {setStudentInfoStatus(0);});};const userInfoStatus = useRef();return (<>//当点击Button的时候获取StudentStatusForm 子组件的onFinish方法<Button onClick={onClickConfirmStudentStatusInfo }>获取onFinish方法</Button><StudentStatusForm ref={userInfoStatus} initialValues={studentDetailsData} /></>)}export default StudentBase;
子组件代码
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';import {Form} from 'antd';//子组件不再使用react的React方式来创建,直接通过函数的方式创建,函数子组件接收两个参数,第一个参数是父组件传过来的其它参数,第二个参数是refconst StudentStatusForm = (props: StudentStatusFormType, ref: any) => {const { initialValues } = props;const [form] = Form.useForm();const onFinish = () => {return form;};useEffect(() => {const newInitialValues = {...initialValues}newInitialValues.admissionDate = moment(initialValues.admissionDate);newInitialValues.birthday = moment(initialValues.birthday);form.setFieldsValue(newInitialValues);}, [initialValues]);//react规定,必须使用useImperativeHandle方法,来保存并抛出想要传递给父组件的方法或者数据,第一个参数是ref,第二个参数是函数,返回想要抛出的对象集合useImperativeHandle(ref, () => ({onFinish,}));return (<div className="student-status-info-emdit"><Form {...formItemLayout} form={form}></Form></div>);};//必须通过forwardRef方法抛出函数组件export default forwardRef(StudentStatusForm);
用来保存数据并且不重新渲染页面
不常用却好用的useref骚操作
在react中,无论是使用usestate来保存数据,如果这数据被修改,将会引起页面的重新渲染。
可有时候,我们想要保存的数据不大,但当数据改变的时候不想页面重新渲染,这份数据在页面多次重新渲染后仍然能保持不变。
要做到以上条件使用什么方法呢?
1 reducer 感觉多少还是有些麻烦,
2 保存到浏览器locationstoreage,取的时候也麻烦,不安全。
3 保存到服务器,可能你会被骂死,这么一点小数据还要麻烦后端。
4 保存到useref里面去。
import React, { useState, useEffect, useMemo, useRef } from 'react';export default function App(props){const [count, setCount] = useState(0);const doubleCount = useMemo(() => {return 2 * count;}, [count]);// 创建useRefconst timerID = useRef();useEffect(() => {// 不从useRef取值,而是赋值给它,用来保存定时器格外酸爽timerID.current = setInterval(()=>{setCount(count => count + 1);}, 1000);}, []);useEffect(()=>{if(count > 10){// 当你需要使用的时候,依然存在,停掉定时器,clearInterval(timerID.current);}});return (<>//绑定ref<button ref={couterRef} onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button></>);}
当useRef与typescript相遇限制useRef的类型
子组件
import React, { useEffect, useState, forwardRef, useImperativeHandle, memo } from 'react';import { Modal, Form } from 'antd';type ModalDetailsProps = {};export interface ModalDetailsRefInterface {initDataFunction: (id:number) => void;}const DetailsModal = forwardRef<ModalDetailsRefInterface, ModalDetailsProps>((_, ref) => {const [formRef] = Form.useForm();/** 控制modal是否显示 */const [modalVisible, setModalVisible] = useState<boolean>(false);const onCancel = () => {setModalVisible(false);};/** 获取id,请求详情数据 */const initDataFunction = (id:number) => {console.log(id)setModalVisible(true);}/** 将初始化数据方法抛出给父组件 */useImperativeHandle(ref, () => ({initDataFunction}));const modalProps = {visible: modalVisible,title: '查看详情',width: 500,onCancel,footer: false,};useEffect(() => {if (modalVisible) {formRef.resetFields();}}, [modalVisible, formRef]);return (<Modal getContainer={false} {...modalProps}><div>123</div></Modal>);});export default memo(DetailsModal);
父组件
import React, { useRef } from 'react';import { Button } from 'antd';import DetailsModal, {ModalDetailsRefInterface,} from '../funding-application-details/funding-application-details';const FundingApplicationList: React.FC = () => {/** 申请资助学生详情 */const DetailsModalRef = useRef<ModalDetailsRefInterface>(null);/** 点击查看详情 */const onClickViewDetails = (fundingId: number) => {DetailsModalRef.current?.initDataFunction(fundingId);};return <><ButtononClick={() => {onClickViewDetails(2);}}>查看详情</Button><DetailsModal ref={DetailsModalRef} /></>}
