ReactRefs转发实现流程详解
Refs转发
概述
- 将ref自动地通过组件传递到子组件的技巧
- 父组件可以通过ref操作子组件,直接使用子组件的DOM
转发refs到DOM组件
渲染原生 DOM 元素 button 的 FancyButton 组件(子组件)
function FancyButton(props) {
return (
<button className="FancyButton">
{props.children}
</button>
)
}
Ref 转发是一个可选特性,其允许某些组件接收 ref,并将其向下传递给子组件
//子组件
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
))
//父组件
//可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
//这样,在父组件中可以直接使用DOM button
以下是对上述示例发生情况的逐步解释:
- 通过调用 React.createRef 创建了一个 React ref 并将其赋值给 ref 变量
- 指定 ref 为 JSX 属性,将其向下传递给 FancyButton React
- 传递ref给forwardRef作为其第二个参数
- 向下转发ref参数到button,并将其指定为JSX属性
- 当ref挂载完成,ref.current将指向button DOM节点
组件库维护者的注意事项
当使用forwardRf时,应将其视为一个新的主版本
在高阶组件中转发refs
转发ref对高阶组件是很有用的,让我们从一个输出组件props到控制台的高阶组件为例
function logProps(WrappedComponent) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return LogProps;
}
logProps组件是一个高阶组件,props将会传递到其包裹的组件。这个高阶组件可以记录所有传递到fancyButton组件的props
class FancyButton extends React.Component {
focus() {
// ...
}
// ...
}
// 我们导出 LogProps,而不是 FancyButton。
// 虽然它也会渲染一个 FancyButton。
export default logProps(FancyButton)
需要注意:refs 将不会透传下去。这是因为 ref 不是 prop 属性。就像 key 一样,其被 React 进行了特殊处理
如果对 HOC 添加 ref,该 ref 将引用最外层的容器组件,而不是被包裹的组件
意味着用于我们 FancyButton 组件的 refs 实际上将被挂载到 LogProps 组件
import FancyButton from './FancyButton';
const ref = React.createRef();
// 我们导入的 FancyButton 组件是高阶组件(HOC)LogProps。
// 尽管渲染结果将是一样的,
// 但我们的 ref 将指向 LogProps 而不是内部的 FancyButton 组件!
// 这意味着我们不能调用例如 ref.current.focus() 这样的方法
<FancyButton
label="Click Me"
handleClick={handleClick}
ref={ref}
/>;
解决办法:可以使用 React.forwardRef API 明确地将 refs 转发到内部的 FancyButton 组件。React.forwardRef 接受一个渲染函数,其接收 props 和 ref 参数并返回一个 React 节点
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// 注意 React.forwardRef 回调的第二个参数 “ref”。
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
// 然后它就可以被挂载到被 LogProps 包裹的子组件上。
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
在 DevTools 中显示自定义名称
下面的组件将在DevTools中显示为“ForwardRef”
const WrappedComponent = React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
})
如果命名了渲染函数,DevTools 也将包含其名称(例如 “ForwardRef(myFunction)”)
const WrappedComponent = React.forwardRef(
function myFunction(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
)
设置函数的 displayName 属性来包含被包裹组件的名称
function logProps(Component) {
class LogProps extends React.Component {
// ...
}
function forwardRef(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
// 在 DevTools 中为该组件提供一个更有用的显示名。
// 例如 “ForwardRef(logProps(MyComponent))”
const name = Component.displayName || Component.name;
forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
}
到此这篇关于React Refs转发实现流程详解的文章就介绍到这了,更多相关React Refs转发内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341