React Refs
- React 支持一种非常特殊的属性 ref,可以用来绑定到 render() 输出的任何组件上;
- ref 的值的类型:
- 当 ref 属性用于 HTML 元素时,则值是 DOM 元素;
- 当 ref 属性用于自定义 Class 组件 时,则值是 组件实例;
- 函数组件上不可以使用 ref 属性,因为函数组件没有实例;
绑定 Ref 的方式
React.createRef(推荐)
通过 React.createRef() 创建出来的对象;
使用时获取到创建的对象其中有一个 current 属性就是对应的元素;
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
// this.myRef = { current: null }; // 两种方式等价
}
changeText() {
this.myRef.current.innerHTML = "hello world";
}
render() {
return (
<div>
<h2 ref={this.myRef}>Hello Create Ref</h2>
<button onClick={(e) => this.changeText()}>改变文本</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 MyComponent 组件
root.render(<MyComponent />);
回调函数
该函数会在 DOM 被挂载时进行回调,这个函数会传入一个 元素对象,可以自己保存,使用时,直接拿到之前保存的元素对象即可;
函数的调用时间:
- componentDidMount 的时候会调用该函数,在 componentDidMount 事件中可以使用 ref;
- 如果 ref 的值发生了变动(旧的函数被新的函数替代),分别调用旧的函数以及新的函数,时间点出现在 componentDidUpdate 之前;
- 旧的函数被调用时,传递 null;
- 新的函数被调用时,传递对象;
- 如果 ref 所在的组件被卸载,会调用函数;
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = null;
this.myRef2 = null;
}
changeText() {
this.myRef.focus();
this.myRef2.focus();
this.setState({});
}
getRef(el) {
this.myRef2 = el;
}
render() {
return (
<div>
{/* 会被调用多次,不推荐 */}
<input ref={(el) => {
console.log('被调用了...', el);
this.myRef = el;
}} type="text" />
{/* 推荐 */}
<input ref={(e) =>this.getRefFn(e)} type="text" />
<button onClick={(e) => this.changeText()}>改变文本</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 MyComponent 组件
root.render(<MyComponent />);
字符串(不推荐)
使用时通过 this.refs.传入的字符串 格式获取对应的元素;
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
changeText() {
this.refs.myRef.innerHTML = "hello world";
}
render() {
return (
<div>
<h2 ref="myRef">String Ref</h2>
<button onClick={(e) => this.changeText()}>改变文本</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 MyComponent 组件
root.render(<MyComponent />);
useRef Hook
在函数组件中,可以使用 useRef Hook 创建 refs;
const MyComponent = () => {
const myRef = useRef(null);
const changeText = () => {
myRef.current.innerHTML = "hello world";
};
return (
<div>
<h2 ref={myRef}>String Ref</h2>
<button onClick={(e) => changeText()}>改变文本</button>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 MyComponent 组件
root.render(<MyComponent />);
Ref 转发
ref 转发 是一种让你在组件外部调用组件内部的 DOM 元素 或者 子组件实例 的技术;
这是一个很重要的概念,尤其是在处理表单元素、处理高阶组件、DOM 操作或者管理第三方 DOM 库集成时非常有用;
forwardRef 方法:
- 参数,传递的是函数组件,不能是类组件,并且,函数组件需要有第二个参数来得到 ref;
- 返回值,返回一个新的组件;
// 3. 函数组件:接收第二个参数,获取转发过来的 ref,并将 ref 绑定到任意元素上
function A(props, ref) {
return <h1 ref={ref}>
组件A
<span>{props.words}</span>
</h1>
}
// 1. 传递函数组件 A,得到一个新组件 NewA
const NewA = React.forwardRef(A);
class App extends React.Component {
ARef = React.createRef()
componentDidMount() {
console.log(this.ARef);
}
render() {
return (
<div>
{/* 2. 将 this.ARef 传递给 NewA 组件内部 */}
<NewA ref={this.ARef} words="asfsafasfasfs" />
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
class A extends React.Component {
render() {
// 4. 类组件接收自定义属性 abc,从而获取到了转发进来的 ref
return <h1 ref={this.props.abc}>
组件A
<span>{this.props.words}</span>
</h1>
}
}
// 1. 将类组件 A 包裹后改造成函数组件,传递该函数组件,得到一个新组件 NewA
const NewA = React.forwardRef((props, ref) => {
// 3. 将转发进来的 ref,用一个非 'ref' 的自定义属性 abc 传递给类组件
return <A {...props} abc={ref} />
})
class App extends React.Component {
ARef = React.createRef();
componentDidMount() {
console.log(this.ARef);
}
render() {
return (
<div>
{/* 2. 将 this.ARef 传递给 NewA 组件内部 */}
<NewA ref={this.ARef} words="asfsafasfasfs" />
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
Redux✍️ react-redux
上一篇