1、React.createRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactCreateRef.jshtml
做用:
獲取目標element
的DOM
實例react
使用:git
import React from 'react' export default class Father extends React.Completed{ constructor(props){ super(props) this.father=React.createRef() } componentDidMount(){ this.father.current.value='hahhaha' } render(){ return <div ref={this.father}> this is div </div> } }
源碼:github
import type {RefObject} from 'shared/ReactTypes'; // an immutable object with a single mutable value //可修改value的 不可變的對象 //沒見過這種寫法 :RefObject export function createRef(): RefObject { //初始化ref對象,屬性current初始值爲null const refObject = { current: null, }; if (__DEV__) { Object.seal(refObject); } return refObject; }
解析:
源碼比較簡單,就是返回了帶有current
屬性的refObject
api
2、React.forwardRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/forwardRef.jsantd
做用:
從父組件中獲取子組件是FunctionComponent
的DOM
實例dom
使用:ide
import React from 'react' //funciton component是沒有dom實例的,由於它是PureComponent,因此沒有this, // 因此不能經過createRef()來拿到實例 //將Father的father傳給子組件,並綁定子組件的DOM實例,從而能在父組件拿到子組件的DOM實例 const Child=React.forwardRef((props,ref)=>{ return <div ref={ref}>child div</div> }) export default class Father extends React.Completed{ constructor(props){ super(props) this.father=React.createRef() } componentDidMount(){ this.father.current.value='hahhaha' } render(){ return <Child ref={this.father} /> } }
源碼:ui
import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols'; import warningWithoutStack from 'shared/warningWithoutStack'; export default function forwardRef<Props, ElementType: React$ElementType>( render: (props: Props, ref: React$Ref<ElementType>) => React$Node, ) { //__DEV__可不看 if (__DEV__) { if (render != null && render.$$typeof === REACT_MEMO_TYPE) { warningWithoutStack( false, 'forwardRef requires a render function but received a `memo` ' + 'component. Instead of forwardRef(memo(...)), use ' + 'memo(forwardRef(...)).', ); } else if (typeof render !== 'function') { warningWithoutStack( false, 'forwardRef requires a render function but was given %s.', render === null ? 'null' : typeof render, ); } else { warningWithoutStack( // Do not warn for 0 arguments because it could be due to usage of the 'arguments' object render.length === 0 || render.length === 2, 'forwardRef render functions accept exactly two parameters: props and ref. %s', render.length === 1 ? 'Did you forget to use the ref parameter?' : 'Any additional parameter will be undefined.', ); } if (render != null) { warningWithoutStack( render.defaultProps == null && render.propTypes == null, 'forwardRef render functions do not support propTypes or defaultProps. ' + 'Did you accidentally pass a React component?', ); } } return { //被forwardRef包裹後,組件內部的$$typeof是REACT_FORWARD_REF_TYPE $$typeof: REACT_FORWARD_REF_TYPE, //render即包裝的FunctionComponent,ClassComponent是不用forwardRef的 render, }; }
解析:
(1)不看__DEV__
的話,返回的也是一個Object,也就是說,Child
被forwardRef
包裹後,React.forwardRef(Child)
的$$typeof
是REACT_FORWARD_REF_TYPE
this
注意:
一旦在Father
組件中,用JSX
引用了Child
組件,那麼就是React.createElement(React.forwardRef(Child))
,又包裹了一層,此時的$$typeof`是`REACT_ELEMENT_TYPE`,`type`是`React.forwardRef(Child)`,`type`裏面的`$$typeof
是REACT_FORWARD_REF_TYPE
const ReactElement = function(type,...) { const element = { $$typeof: REACT_ELEMENT_TYPE, type: type, }; }
(2)關於forward
在高階組件的用法,請參考:https://reactjs.org/docs/react-api.html#reactforwardref
(3)如何在antdPro
/FunctionComponent
中使用:
子:
const Child = (props,ref) => { const inputRef = React.useRef(); React.useImperativeHandle(ref, () => ({ focus: () => { // inputRef.current.focus(); inputRef.current.value='aaaa' } })); return (<input type="text" ref={inputRef}/>) } export default React.forwardRef(Child)
父:
import Child from './Child'; const Father=(props)=> { const rref= React.useRef(null) useEffect(() => { //console.log(rref.current,'rref33') rref.current.focus() }, []); return (<Child ref={rref}/>) }
注意:
① antdPro
中使用的話,我試了是很差用dva
的connect
包裹的,issue
上做者也沒回答,就關閉了:https://github.com/ant-design/ant-design-pro/issues/3123
② useImperativeMethods
已經重命名爲useImperativeHandle
,傳送門:https://github.com/facebook/react/pull/14565
(完)