1.高阶组件:就是一个函数(不算是函数组件,但是可以理解为函数组件,因为函数组件本质上就是一个函数而已)返回值是一个新的组件(函数组件或者 class 组件)
2.forwardRef主要是为了给 函数组件/高阶组件函数 增加接收 ref 的能力(也就是在组件标签上写 ref属性,内部可以进行接收),以便可以在内部使用 Ref 作用于内部元素!
React.forwardRef 详解
React.forwardRef(render)
的返回值是react
组件,接收的参数是一个 render
函数,函数签名为render(props, ref)
,第二个参数将其接受的 ref 属性转发到render
返回的组件中。
这项技术并不常见,但在以下两种场景中特别有用:
- 转发
ref
到组件内部的DOM
节点上 - 在高阶组件中转发
ref
1. 转发 ref
到组件内部的DOM
节点
ref
的值根据节点的类型而有所不同:
- 当
ref
属性用于 HTML 元素时,接收底层 DOM 元素作为其current
属性。 - 当
ref
属性用于自定义 class 组件时,ref
接收组件实例作为其current
属性。 - 不能在函数组件上使用
ref
属性,因为他们没有实例。
函数组件使用 Ref:
jsximport React, { useRef } from 'react'; function MyComponent() { const ref = useRef(null); // 在需要时访问ref const handleClick = () => { console.log(ref.current); }; return ( <div> <h1 ref={ref}>Hello, World!</h1> <button onClick={handleClick}>Click Me</button> </div> ); }
jsx
// App.js
import React from 'react';
import Foo from './component/Foo';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.input = React.createRef(); // 1
// ↑5
}
handleClick = (e) => {
const input = this.input.current;
// 6
console.log(input);
console.log(input.value);
input.focus();
}
render() {
return (
<>
<button onClick={this.handleClick}>click to get value</button>
{/*2*/}
<Foo ref={this.input}/>
</>
)
}
}
jsx
// Foo.jsx
import React from 'react';
// 3
const Foo = React.forwardRef((props, myRef) => {
return (
<div>
<p>....一些其他节点</p> {/*4*/}
<input type="text" defaultValue='ref 成功转发到 Foo 组件内部的 input节点上' ref={myRef}/>
<p>....一些其他节点</p>
<p>....一些其他节点</p>
</div>
);
});
export default Foo;
2. 在高阶组件中转发ref
jsx
// App.js
import React from 'react';
import logProps from './component/logProps';
import Bar from './component/Bar'
const BarWithLogProps = logProps(Bar);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Roman',
age: 23,
hobby: 'video game'
}
this.myRef = React.createRef();
}
handleClick = (e) => {
this.setState({
name: 'fxy',
age: 32,
hobby: 'swim'
});
console.log(this.myRef.current);
}
render() {
return (
<div>
<button onClick={this.handleClick} >click to change props</button>
<BarWithLogProps {...this.state} ref={this.myRef} />
</div>
);
}
}
jsx
// 最终形态
import React from 'react';
export default function logProps(WrappedComponent) {
class LogProps extends React.Component {
// 2
constructor(props) {
super(props);
this.state = {
message: '这是LogProps'
}
}
componentDidUpdate(prevProps) {
console.log('Previous props: ', prevProps);
console.log('Current props: ', this.props);
}
render() {
// 3
const {customRef, ...props} = this.props;
// 3.5 return <WrappedComponent {...this.props}/>;
return <WrappedComponent {...props} ref={customRef} />;
}
}
// return LogProps;
return React.forwardRef((props, ref) => (
// 1
<LogProps {...props} customRef={ref} />
))
}