当前位置: 首页 > 后端技术 > Node.js

ReactRef其实是这样的

时间:2023-04-04 01:07:59 Node.js

大家好,我是墨口,好久没冒泡了,最近一直在看研究算法和数据结构,不过貌似很多前端不喜欢看这种东西,目前我的算法也很郁闷,就不秀丑了。当然最近也开始研究React。这篇文章主要是关于Ref.相关的内容。如有错误请指正。ref的由来在典型的React数据流中,props是父组件与子组件交互的唯一途径。要修改子组件,您需要使用新的道具重新渲染它。但是,在某些情况下,您需要在典型数据流之外强制修改子组件/元素。何时使用refs:管理焦点、文本选择或媒体播放。触发强制动画。集成第三方DOM库。ref的三种方式在Reactv16.3之前,ref是以字符串(stringref)或回调函数(callbackref)的形式获取的。ref通过char获取://stringrefclassMyComponentextendsReact.Component{componentDidMount(){this.refs.myRef.focus();}render(){返回;}}refviacallbackFunctionget://callbackrefclassMyComponentextendsReact.Component{componentDidMount(){this.myRef.focus();}render(){return{this.myRef=ele;}}/>;在v16.3中,通过0017-new-create-ref提议引入了一个新的API:React.createRef。ref是通过React.createRef获得的://React.createRefclassMyComponentextendsReact.Component{constructor(props){super(props);this.myRef=React.createRef();}componentDidMount(){this.myRef.current.focus();}render(){return;}}将被移除的stringref先说stringref,stringref被诟病很久了,React官方文档中声明:“如果你当前正在使用this.refs.textInput来访问refs,我们推荐使用回调函数或createRefAPI代替。”,为什么这么糟糕?最初由React作者之一丹·阿布拉莫夫(danabramov)编写。发布于https://news.ycombinator.com/edit?id=12093234,(此站点需要梯子)。投诉主要有以下几点:stringref不能合并。比如第三方库的父组件给子组件传了ref,那我们就不能给子组件加上ref了。另一方面,回调引用没有所有者,因此您可以随时编写它们。例如:/**stringref**/classParentextendsReact.Component{componentDidMount(){//可以获得this.refs.childRefconsole.log(this.refs);}render(){const{children}=this.props;返回React.cloneElement(children,{ref:'childRef',});}}classAppextendsReact.Component{componentDidMount(){//this.refs.child无法获取console.log(this.refs);}render(){return();}}stringref的所有者由当前正在执行的组件决定。这意味着使用常见的“渲染回调”模式(如反应),错误的组件将拥有引用(它最终将在反应而不是你的组件上定义renderRow)。classMyComponentextendsComponent{renderRow=(index)=>{//stringref将挂载到DataTablethisreturn;//回调ref将挂载在MyComponent上thisreturnthis['input-'+index]=input}/>;}render(){return}}stringref不适合像Flow这样的静态分析。Flow无法猜测框架可以使字符串ref在React上“出现”的神奇效果,以及它的类型(可能会有所不同)。回调引用比静态分析更友好。字符串ref强制React跟踪当前正在执行的组件。这是有问题的,因为它使反应模块有状态,并在将反应模块复制到包中时导致奇怪的错误。在reconciliation阶段,在创建和更新ReactElement的过程中,ref会被封装成一个闭包函数,等待commit阶段执行,这会对React的性能造成一定的影响。关于这一点,可以参考React源码中coerceRef的实现:在协调子节点的过程中,会对stringref进行处理,转化为method。这个方法最主要的是设置了instance.refs[stringRef]=element,相当于把它转化成了一个函数ref。对于更新过程中stringref是否变化,需要和current.ref._stringRef进行比较。如果在上次渲染中使用了它,这将记录字符串ref的值。owner是在调用createElement时获取的,通过ReactCurrentOwner.current获取。该值将在更新组件之前设置。比如在更新ClassComponent的时候,会在调用render方法之前设置,然后调用render的时候就可以获取到对应的owner。强回调refReact会在组件挂载时调用ref回调函数并传递DOM元素,在组件卸载时调用它并传递null。在componentDidMount或componentDidUpdate被触发之前,React将确保refs必须是最新的。如果ref回调函数定义为内联函数,在更新过程中会执行两次,第一次传递参数null,第二次传递参数DOM元素。这是因为在每次渲染时都会创建一个新的函数实例,因此React会清除旧的ref并设置新的。将ref回调函数定义为类的绑定函数可以避免上述问题,但在大多数情况下是无关紧要的。最新的React.createRefReact.createRef的优点:与callbackref相比,React.createRef更加直观,避免了一些callbackref的理解问题。React.createRef的缺点:性能略低于callbackref,能力上还是不如callbackref。比如上一节提到的组合问题,createRef也是无能为力。ref的值因节点类型而异:当ref属性用于HTML元素时,在构造函数中使用React.createRef()创建的ref接收底层DOM元素作为其当前属性。当ref属性用于自定义类组件时,ref对象接收组件的已安装实例作为其当前属性。默认情况下,你不能在函数组件上使用refprops(可以在函数组件内部使用),因为它们没有实例:如果你想在函数组件中使用ref,你可以使用forwardRef(可以与useImperativeHandle结合使用)或者你可以使用该组件转化为类组件。refs转发是否需要将DOMrefs暴露给父组件?在极少数情况下,您可能希望在父组件中引用子组件的DOM节点。通常不推荐这样做,因为它会破坏组件的封装,但它偶尔可以用于触发焦点或测量子DOM节点的大小或位置。如何将ref暴露给父组件?如果您使用的是React16.3或更高版本,我们建议在这种情况下使用ref转发。引用转发允许组件公开子组件引用,就好像它们是它们自己的引用一样。什么是参考转发?constFancyButton=React.forwardRef((props,ref)=>({props.children}));//可以直接获取DOM按钮:constref=React.createRef();Clickme!;低版本怎么转发?如果你使用的是React16.2或更低版本,或者如果你需要比ref转发更灵活,你可以将ref作为一个特别命名的prop直接传递。例如,如下:);this.inputElement=React.createRef();}render(){return();}}下面是对上面示例中发生的事情的逐步解释:我们通过调用React.createRef创建了一个Reactref并将其分配给ref变量。我们通过将ref指定为JSX属性将其传递给。React将ref传递给forwardRef内部函数(props,ref)=>...作为它的第二个参数。我们将该ref参数转发给,将其指定为JSX属性。挂载ref后,ref.current将指向