React ref 多場景使用教程(附demo)

React ref 多場景使用教程

React16.8 後,咱們就不斷的擁抱 Hook 開發,在組件化開發已經成爲咱們必不可缺的開發方式時,ref 的使用就顯得尤其重要。react

可是 class 開發依舊被大部分人所使用,因此咱們來分析幾種使用 ref 的場景。git

下面存在幾種場景:github

  • 父組件: class, 子組件: class
  • 父組件: hook, 子組件: hook
  • 父組件: class, 子組件: hook
  • 父組件: hook, 子組件: class

上面場景若是在 dva 中使用會有問題,每種場景會對此進行分析redux

下面經過這幾種場景分析:如何在 父組件 調用 子組件內部方法以及 數據瀏覽器

1、父組件: class, 子組件: class

一、子組件不使用 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

2、父組件: hook, 子組件: hook

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;
複製代碼

3、父組件: class, 子組件: hook

這種狀況下直接參考 2、父組件: hook, 子組件: hook 便可。將不在詳細說明,demo 中也不作展現。

4、父組件: hook, 子組件: class

對於 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 便可。

完整 demo 從這裏進入哈,給個 star 多多支持

編寫不易,點點關注給個贊呀~

相關文章
相關標籤/搜索