同一组件内部,通过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(); //创建useRef
useEffect(() => {
document.title = `The value is ${count}`;
//通过couterRef 的current 属性可以获取到button这个dom
console.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方式来创建,直接通过函数的方式创建,函数子组件接收两个参数,第一个参数是父组件传过来的其它参数,第二个参数是ref
const 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]);
// 创建useRef
const 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 <>
<Button
onClick={() => {
onClickViewDetails(2);
}}
>
查看详情
</Button>
<DetailsModal ref={DetailsModalRef} />
</>
}