ReactHook ImperativeHandleHook以及React.forwardRef

React.forwardRef
	因为组件标签上的ref是直接绑定到组件最外层上,无法通过props再传递到组件的内部内容上
	forwardRef使得父组件能够操作子组件内部的ref
	
	1、子组件
		const 子组件 = React.forwardRef((props, ref) => {
		return(
			  <div>
			    <input ref={ref} type="text" />
			    <button>{props.children}</button>
			  </div>
			)
		});
		
	2、父组件
	将父组件的ref绑定到子组件上就可操控子组件,ref.current.xxx
		function App() {
		  const ref = useRef();
		  return (
		    <div>
		      <子组件 ref={ref}>Click Me</子组件>
		    </div>
		  )
		}
	
	3、高阶组件中的应用
		function logProps(Component) {
		  class SuffLogProps extends React.Component {
		    componentDidUpdate(prevProps) {
		      console.log('old props:', prevProps);
		      console.log('new props:', this.props);
		    }
		
		    render() {
		      const {forwardedRef, ...rest} = this.props;
		
		      然后就可以被挂载到被 SuffLogProps 包裹的子组件上。
		      
		      return <Component ref={forwardedRef} {...rest} />;
		    }
		  }
		
		 将自定义的prop属性 “forwardedRef” 定义为ref
		  return React.forwardRef((props, ref) => {
		    return <SuffLogProps {...props} forwardedRef={ref} />;
		  });
		}
	
	4、在React  Devtools中自定义forwardedRef转发组件显示的内容
		const WrappedComponent = React.forwardRef((props, ref) => {	显示为 “ForwardRef”
		  return <LogProps {...props} forwardedRef={ref} />;
		});
		
		const WrappedComponent = React.forwardRef(	显示为“ForwardRef(myFunction)”
		  function myFunction(props, ref) {
		    return <LogProps {...props} forwardedRef={ref} />;
		  }
		);
		
		function logProps(Component) {		显示为“ForwardRef(logProps(MyComponent))”
		  class LogProps extends React.Component {
		    // ...
		  }
		  function forwardRef(props, ref) {
		    return <LogProps {...props} forwardedRef={ref} />;
		  }
		  const name = Component.displayName || Component.name;
		  forwardRef.displayName = `logProps(${name})`;
		
		  return React.forwardRef(forwardRef);
		}
		
ImperativeHandleHook
	当使用React.forwardRef时,父组件的ref和子组件的ref都是同一个ref
	当使用ImperativeHandleHook,可以使得父组件和子组件拥有各自的ref,并且子组件可选择性地暴露其他内容
	
	1、子组件
		const 子组件= React.forwardRef((props, ref) => {
		  const inputRef = useRef();
		  
		  useImperativeHandle(ref, () =>{
			  return{  暴露给父组件的ref的值
		  			focus: () => {
		      			inputRef.current.focus();
		    		},
		    		其他内容...
		  		}
		  });
		
		  return <input ref={inputRef} type="text" />
		});
		
	2、父组件
		将父组件的ref绑定到子组件上,就可获取子组件通过ref暴露的内容,父组件Ref.current.子组件暴露的内容
		const App = props => {
		  const 父组件Ref = useRef();
			
		  return (
		    <div>
		    
		      <子组件 ref={fancyInputRef} />
		      
		      <button
		        onClick={() => fancyInputRef.current.focus()}
		      >父组件调用子组件的 focus</button>
		      
		    </div>
		  )
		}

代码示例:
React.forwardRef:

import React, { useCallback, useRef } from 'react';
import ReactDOM from 'react-dom';

// 实现 ref 的转发
const FancyButton = React.forwardRef((props, ref) => (
  <div>
    <input ref={ref} type="text" />
    <button>{props.children}</button>
  </div>
));

// 父组件中使用子组件的 ref
function App() {
  const ref = useRef();
  const handleClick = useCallback(() => ref.current.focus(), [ ref ]);

  return (
    <div>
      <FancyButton ref={ref}>Click Me</FancyButton>
      <button onClick={handleClick}>获取焦点</button>
    </div>
  )
}

ReactDOM.render(<App />, root);

ImperativeHandleHook:

import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />
});

const App = props => {
  const fancyInputRef = useRef();

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button
        onClick={() => fancyInputRef.current.focus()}
      >父组件调用子组件的 focus</button>
    </div>
  )
}

ReactDOM.render(<App />, root);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值