CPPAlien / JS-QA

前端知识问答
0 stars 0 forks source link

react 中 refs 的几种方法 #8

Open CPPAlien opened 5 years ago

CPPAlien commented 5 years ago

字符串方式

优点:简便 缺点: 1,后续版本可能会被移除; 2,针对静态类型检测不支持 3,影响性能 4,对复杂用例难以实现:需要向父组件暴露dom;单个实例绑定多个dom

Callback 方式

class CustomTextInput extends Component{
    constructor(props){
        super(props);
        this.textInput = null;
        this.focus = this.focus.bind(this);
    }

    focus(){
        if(this.textInput){
            this.textInput.focus();
        }
   }
    render(){
        return(
            <div>
                <input type="text"  ref = {(input) => {this.textInput = input}}/>
                <input type="button" value = "Focus the text input" onClick={this.focus}/>
            </div>
        )
    }
}

组件挂载时,调用该函数,组件卸载时再次调用,参数为null。ref回调调用发生在在componentDidMount或者componentDidUpdate生命周期回调方法调用之前

缺点:

1,每次组件重新渲染的时候,行内函数都会执行两次,第一次的ele的值为空,第二次才为真正的DOM对象。

2,如果我们想要将一个子组件的ref传递给父组件,会有点麻烦,虽然通过一个特殊的prop属性可以做到,但是感觉有点不太正规

function Foo(props) {
  return <div>
            <input type="text" ref = {props.inputEle}/>
          </div>
}

class Fn extends React.Component {
  constructor(props) {
    super(props);
    this.handle = this.handle.bind(this);
  }
  render() {
    return <div>
    <Foo inputEle = {el => {this.eleInput = el; console.log(el)}}/> // el为子组件上对应的DOM节点
      <button onClick = {this.handle}>聚焦</button>
      </div>
  }

  handle() {
    this.eleInput.focus();
  }
}

React.createRef

React 16 引入

import { CustomTextInput } from "./CustomTextInput"
class AutoFocusTextInput extends Component{
    constructor(props){
        super(props);
        this.textInput = React.createRef()
    }

    componentDidMount(){
        this.textInput.current.textInput.focus();
    }

    render(){
        return(
            <CustomTextInput ref = {this.textInput}/>
        )
    }
}
export default AutoFocusTextInput;

ref 的传递。在函数组件中用法

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

HOC 组件中用法

class FancyButton extends React.Component {
  focus() {
    // ...
  }

  // ...
}

// Rather than exporting FancyButton, we export LogProps.
// It will render a FancyButton though.
export default logProps(FancyButton);
import FancyButton from './FancyButton';

const ref = React.createRef();

// The FancyButton component we imported is the LogProps HOC.
// Even though the rendered output will be the same,
// Our ref will point to LogProps instead of the inner FancyButton component!
// This means we can't call e.g. ref.current.focus()
<FancyButton
  label="Click Me"
  handleClick={handleClick}
  ref={ref}
/>;
function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;

      // Assign the custom prop "forwardedRef" as a ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }

  // Note the second param "ref" provided by React.forwardRef.
  // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
  // And it can then be attached to the Component.
  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}