共计 3766 个字符,预计需要花费 10 分钟才能阅读完成。
一、React.createRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactCreateRef.js
作用:
获取目标 element
的DOM
实例
使用:
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>
}
}
源码:
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
二、React.forwardRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/forwardRef.js
作用:
从父组件中获取子组件是 FunctionComponent
的DOM
实例
使用:
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} />
}
}
源码:
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
注意:
一旦在 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
(完)