React16.8 後,咱們就不斷的擁抱 Hook 開發,在組件化開發已經成爲咱們必不可缺的開發方式時,ref 的使用就顯得尤其重要。react
可是 class 開發依舊被大部分人所使用,因此咱們來分析幾種使用 ref 的場景。git
下面存在幾種場景:github
上面場景若是在 dva
中使用會有問題,每種場景會對此進行分析redux
下面經過這幾種場景分析:如何在 父組件
調用 子組件內部
的 方法
以及 數據
。瀏覽器
dva
狀況子組件不須要任何多餘的操做, 直接編寫父組件便可。antd
...
import { Button } from 'antd-mobile';
import { NoDvaSon } from './components'; // 不是用 dva 的子組件
@connect(({ classclass }) => ({ classclass }))
class ClassclassPage extends Component {
noDvaChild: any;
getSonEvent = () => {
this.noDvaChild.noDvaSonEvent(); // 這裏調用子組件的方法
console.log(this.noDvaChild.state); // 這裏獲取子組件的 state 值
};
render() {
return (
<div> <Button onClick={this.getSonEvent}>調用子組件的方法</Button> <NoDvaSon ref={(e) => { this.noDvaChild = e; }} /> </div> ); } } export default ClassclassPage; 複製代碼
dva
狀況父組件同樣按照上面的編寫方式不變,只不過子組件加上了 dva
,保存後打開頁面,瀏覽器的 Console
就會有如下的警告。組件化
這時咱們點擊父組件的按鈕調用子組件的方法和數據時,就會報錯。ui
接下來咱們來修改 子組件的代碼:this
修改 connect 的字段:spa
const mapDispatchToProps = (dispatch, ownProps) => {
return { dispatch };
};
@connect(({ classclass }) => ({ classclass }), mapDispatchToProps, null, { forwardRef: true }) // 新 react-redux 版本支持
@connect(({ classclass }) => ({ classclass }), mapDispatchToProps, null, { withRef: true }) // 舊 react-redux 版本支持
複製代碼
只要引入 forwardRef
或者 withRef
報錯就迎刃而解。
在寫 demo 時我使用的是 withRef
發現瀏覽器 Console
仍是報錯,並提示 withRef
不能使用,因此就換成了 forwardRef
。
在 hook
中,使用 dva
不會影響到 ref
的使用。
父組件代碼:
import React, { FC, useRef } from 'react';
import { Button } from 'antd-mobile';
import { NoDvaSon } from './components';
const HookhookPage: FC = () => {
const childRef = useRef();
const getSonEvent = () => {
childRef.current.click(); // 調用子組件的方法
console.log(childRef.current.value); // 獲取子組件的數據
};
return (
<div className={styles.center}> <Button onClick={getSonEvent}>調用子組件的方法</Button> {/* 子組件引入 cRef 這個名字可隨便定義 */} <NoDvaSon cRef={childRef} /> </div> ); } export default connect(({ hookhook }) => ({ hookhook }))(HookhookPage); 複製代碼
子組件代碼:
import React, { FC, useState, useImperativeHandle } from 'react'; // 引入須要的 useImperativeHandle
interface PageProps {
cRef: any;
}
const Page: FC<PageProps> = ({ cRef }) => {
const [noDvaValue, setNoDvaValue] = useState('noDvaValue');
/** * 這裏是重點!!!! * 此處注意useImperativeHandle方法的的第一個參數是目標元素的ref引用 */
useImperativeHandle(cRef, () => ({
// click 就是暴露給父組件的方法
click: () => {
noDvaSonEvent();
},
value: { noDvaValue },
}));
const noDvaSonEvent = () => {
console.log('this is no dva son event');
};
return <div>this is no dva son</div>;
};
export default Page;
複製代碼
這種狀況下直接參考 2、父組件: hook, 子組件: hook 便可。將不在詳細說明,demo 中也不作展現。
對於 class
類型的子組件來講,實現方法和 1、父組件: class, 子組件: class
差很少。這裏附上代碼供你們參考
對於不使用 dva
的的子組件來講,子組件不須要增長代碼,只須要在父組件上編寫便可:
import React, { FC, useRef } from 'react';
import { HookhookModelState, ConnectProps, connect } from 'alita';
import { Button } from 'antd-mobile';
import { NoDvaClassSon } from './components';
const HookhookPage: FC = ({ hookhook, dispatch }) => {
let classChild: NoDvaClassSon | null = null;
const getclassSonEvent = () => {
classChild.noDvaSonEvent(); // 調用子組件的方法
console.log(classChild.state); // 獲取子組件的數據
};
return (
<div className={styles.center}> <Button onClick={getclassSonEvent}>調用class子組件的方法</Button> <NoDvaClassSon ref={(e) => { // 使用 ref classChild = e; }} /> </div> ); }; export default connect(({ hookhook }) => ({ hookhook }))(HookhookPage); 複製代碼
而使用 dva
的子組件則像 1、父組件: class, 子組件: class
加上 forwardRef: true
便可。
編寫不易,點點關注給個贊呀~