/*
* @Description: ref 的场景和 传送门 Portal 作用以及使用
* @Version: 2.0
* @Autor: lhl
* @Date: 2020-06-01 10:20:33
* @LastEditors: lhl
* @LastEditTime: 2020-06-02 14:07:17
*/
import React, { Component, useRef } from 'react'
import ReactDOM from 'react-dom'
export default class App extends Component {
render() {
return (
<div>
<p>hello react</p>
<FunRef abc="111"></FunRef>
<RefClassComponent></RefClassComponent>
<CbRef></CbRef>
<Dialog></Dialog>
</div>
)
}
}
// 默认情况下,你不能在函数组件上使用 ref 属性,因为它们没有实例
// 但是特别的,你可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件
// 如果要在函数组件中使用 ref,你可以使用 forwardRef 或者可以将该组件转化为 class 组件
function FunRef(props) {
console.log(props) // {abc: "111"}
// 这里必须声明 textInput,这样 ref 才可以引用它
const textInput = useRef(null);
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="聚焦"
onClick={handleClick}
/>
</div>
);
}
// class 组件中ref的使用 如果你目前还在使用 this.refs.xx 这种方式访问 refs ,现在建议用回调函数或 createRef API 的方式代替
class RefClassComponent extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
// 回调函数的方式 访问 refs React.forwardRef 接受一个渲染函数,其接收 props 和 ref 参数并返回一个 React 节点
class CbRef extends Component {
render() {
return (
<FunRef
inputRef={el => this.inputElement = el}
/>
);
}
}
// createPortal 传送门的使用 Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
class Dialog extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
this.el.setAttribute('class', 'dailog-box');
}
componentDidMount() {
document.body.appendChild(this.el);
}
componentWillUnmount() {
document.body.removeChild(this.el);
}
render() {
return ReactDOM.createPortal((
<div className="dailog-content">
弹窗内容
</div>
), this.el);
}
}