React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)

React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第1张图片

「问题」

落日余晖舒云剩影☁️的旁晚

小白:师父,React里面的Refs有什么用啊?

乐闻:先考你一个问题,现在有一个表单,页面加载完成时第一个input框自动获取焦点,不需要人为选中,应该怎么实现?

小白:直接给 input标签加上autoFocus属性呗,例如

乐闻:emm... 这种方式也可以,还有其他的实现方式没?

小白:如果使用jquery的话就好了,可以直接获取到input标签实例,然后调用它的focus()方法就可以实现自动聚焦了。React的话不知道怎么弄。

乐闻:React也提供了我们访问DOM节点的能力,接下来我详细的跟你说说这个refs属性。

「官方定义」

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。

备注:1. DOM节点就是JSX里的div,input等原生标签。

  		2. React元素就是 我们创建的React组件,比如class组件,函数组件。

React推崇「状态决定视图」,页面怎么展示由数据状态控制。但是有些时候这样操作并不是很便捷,甚至不能实现理想功能。

React提供了Refs帮助开发者可以直接操作DOM节点,就像jquery时代一样,直接操作DOM,简单明了。但是官方建议:勿过度使用 Refs。 意思是能不用就不用,除非实在没有办法了。

「使用场景」

  • 管理焦点,文本选择或媒体播放。
  • 触发强制动画。
  • 集成第三方 DOM 库。

「代码实操」

React 组件分为两种 Class组件 + Function组件。两种组件使用Refs的方式也各不相同。

下面列表各种场景下的使用方式,如果举例没有覆盖到的,欢迎留言补充

  • 操作原生DOM

    • class组件
    1. React.createRef( 推荐
    import React, { Component } from "react";
    class RefsDeme extends Component {
      constructor(props) {
        super(props);
        this.state = {};
        this.inputRef = React.createRef();
      }
      componentWillMount() {
        console.log("componentWillMount->inputRef:", this.inputRef);
      }
      componentDidMount() {
        console.log("componentDidMount->inputRef:", this.inputRef);
        this.inputRef.current.focus();
      }
      render() {
        return (
          

            姓名: 
          

        );
      }
    }

    export default RefsDeme;
    React.createRef()
    1. 回调函数方式
    import React, { Component } from "react";
    class RefsDeme extends Component {
      constructor(props) {
        super(props);
        this.state = {};
        this.inputRef = null;
      }
      componentWillMount() {
        
      }
      componentDidMount() {
        this.inputRef.focus();
      }

      render() {
        return (
          

            姓名:{" "}
                      ref={(ref) => {
                this.inputRef = ref;
              }}
            />
          

        );
      }
    }

    export default RefsDeme;
    回调函数方式
    1. string方式( 不推荐,了解即可
    import React, { Component } from "react";
    class RefsDeme extends Component {
      constructor(props) {
        super(props);
        this.state = {};
      }

      componentWillMount() {
        console.log("componentWillMount->inputRef:", this.refs.inputRef);
      }
      componentDidMount() {
        console.log("componentDidMount->inputRef:", this.refs.inputRef);
        this.refs.inputRef.focus();
      }

      render() {
        return (
          

            姓名: 'inputRef' />
          

        );
      }
    }

    export default RefsDeme;
    React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第2张图片
    • function组件

    因为Function组件不存在this,所以function组件不能通过class组件的方式来操作refs。Function组件使用refs,需要用到React Hooks。

    import React, { useRef, useEffect } from "react";

    export default function FunctionRef() {
      const inputRef = useRef();

      useEffect(() => {
        inputRef.current.focus();
      }, []);
      return (
        

          FunctionRef: 
        

      );
    }
    React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第3张图片
  • 操作React组件

    • class组件
    // ClassComponent.js
    import React, { Component } from "react";

    export default class Class extends Component {
      onCheck = (type) => {
        alert("type:" + type);
      };
      render() {
        return "child")}>Class
;
  }
}

// RefsDemo.js
import React, { Component } from "react";
import ClassComponent from "./ClassComponent";
class RefsDeme extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.classRef = React.createRef();
  }
  componentWillMount() {
    console.log("componentWillMount->classRef:", this.classRef);
  }
  componentDidMount() {
    console.log("componentDidMount->classRef:", this.classRef);
  }
  render() {
    return (
        
    );
  }
}

export default RefsDeme;

React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第4张图片

备注:父组件可以获取自组件实例并调用自组件中定义的方法

  • function组件

默认情况下,不能在函数组件上使用 ref 属性,因为它们没有实例

直接对 普通的函数组件使用 ref 属性时会 Warning

React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第5张图片

如果需要操作Function组件的refs,需要通过React.forwardRef高阶组件包裹一层。

// FunctionComponent.js
import React, { useImperativeHandle } from "react";

export default React.forwardRef(function Function(props, ref) {
  const onCheck = (type) => {
    alert("type:" + type);
  };
  //需要把什么属性或者方法传给副组件,通过useImperativeHandle返回
  useImperativeHandle(ref, () => ({
    onCheck: onCheck.bind(null, "father"),
  }));

  return "child")}>Function
;
});

// RefsDemo.js
import React, { Component } from "react";
import FunctionComponent from "./FunctionComponent";
import ClassComponent from "./ClassComponent";
class RefsDeme extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.functionRef = React.createRef();
  }

  componentWillMount() {
    console.log("componentWillMount->functionRef:", this.functionRef);
  }
  componentDidMount() {
    console.log("componentDidMount->functionRef:", this.functionRef);
  }

  render() {
    return (
     

        
                  onClick={() => {
            this.functionRef.current.onCheck();
          }}>
          调用自组件方法
        
      

    );
  }
}

export default RefsDeme;
React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第6张图片

点击自组件触发onCheck方法

image-20201110225637217

点击父组件按钮触发onCheck方法

React进阶教程之Refs详解——通俗易懂,Class组件&Function组件(受控组件与非受控组件)_第7张图片

总结ref提供了一种对于react标准的数据流不太适用的情况下组件间交互的方式, 但是在大多数情况下应该使用react响应数据流那种方式,不要过度使用ref。

普通人还在犹豫的时候,好看的人已经一键三连咯~

「公众号」:乐闻世界

你可能感兴趣的:(#,React,进阶之路,前端知识图谱,react,javascript,refs)