源碼地址:https://github.com/facebook/react/blob/master/packages/react/src/ReactCreateRef.jsreact
三種使用ref方式git
react會在完成這個節點渲染以後,會在this.refs這個對象上掛載這個string對應的一個key,這個key所指向的就是這個節點的實例對象,若是是dom節點就會對應dom的實例,若是是子組件,就會是子組件的實例(也就是class component) 若是是一個function component,正常來說是會失敗的,也就是undefinedgithub
使用createRef建立一個對象,這個對象初始的時候,裏面的current是null,把這個對象傳到某個節點,在這個組件渲染以後,會把這個節點掛載到這個對象的currentredux
// demo import React from 'react' export default class RefDemo extends React.Component { constructor() { super() this.objRef = React.createRef() // { current: null } } componentDidMount() { // console.log(`span1: ${this.refs.ref1.textContent}`) // console.log(`span2: ${this.ref2.textContent}`) // console.log(`span3: ${this.ref3.current.textContent}`) setTimeout(() => { this.refs.stringRef.textContent = 'string ref got' this.methodRef.textContent = 'method ref got' this.objRef.current.textContent = 'obj ref got' }, 1000) } render() { return ( <> <p ref="stringRef">span1</p> <p ref={ele => (this.methodRef = ele)}>span3</p> <p ref={this.objRef}>span3</p> </> ) } } // export default () => { // return <div>Ref</div> // }
demo能看到三種方式都成功獲取到了節點,並更新了節點的值dom
// 源碼解讀 import type {RefObject} from 'shared/ReactTypes'; // an immutable object with a single mutable value export function createRef(): RefObject { const refObject = { current: null, }; if (__DEV__) { Object.seal(refObject); } return refObject; }
源碼其實就這短短几行,返回了一個對象,這個對象中有個current屬性,初始爲null學習
源碼學習地址:https://github.com/facebook/react/blob/master/packages/react/src/forwardRef.jsthis
考慮以下場景spa
咱們是一個組件開發者,寫了不少供用戶使用的開源組件。用戶使用了例如redux的connect鏈接組件,connect實際上是hoc的模式包裹了一層組件,那麼若是用戶在connect的組件上使用ref,就沒法直接掛載到真實組件上。code
能夠考慮使用React.forwardRef(props, ref) 去傳遞一層refcomponent
// demo import React from 'react' const TargetComponent = React.forwardRef((props, ref) => ( <input type="text" ref={ref} /> )) export default class Comp extends React.Component { constructor() { super() this.ref = React.createRef() } componentDidMount() { this.ref.current.value = 'ref get input' } render() { return <TargetComponent ref={this.ref} /> } }
// 源碼解讀 import {REACT_FORWARD_REF_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, ) { ... return { $$typeof: REACT_FORWARD_REF_TYPE, render, }; } /** 返回的是一個對象,對象中有個$$typeof,切忌不能與createElement中的$$typeof弄混。 拿上述demo來講,因爲經過React.forwardRef返回的是一個對象,所以TargetComponent也是一個對象,而在<TargetComponent />從jsx解析爲js中,解析爲React.createElement(type, config, children)中,TargetComponent只是做爲type。 所以 使用React.forwardRef返回的$$typeof仍然是REACT_ELEMENT_TYPE,它的type是咱們拿到的對象{ $$typeof: REACT_FORWARD_REF_TYPE, render, }; 它裏面有個$$typeof,是REACT_FORWARD_REF_TYPE 小結:咱們使用React.forwardRef建立的全部的節點,它的$$typeof都是REACT_ELEMENT_TYPE */