Refs
允许我们访问真实 DOM
一般的,React
数据流是通过 props
来实现父子组件的交互
Refs
允许我们用于强制修改子组件
// 输入框焦点
class MyInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
inputOperating() {
console.log(this.inputRef.current.value);
this.inputRef.current.focus();
}
render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.inputOperating.bind(this)}>获取焦点</button>
</div>
);
}
}
// 媒体管理
class MyVideo extends React.Component {
constructor() {
super();
this.vdoRefs = React.createRef();
}
vdoPause() {
this.vdoRefs.current.pause();
}
vdoPlay() {
this.vdoRefs.current.play();
}
render() {
return (
<div>
<video
ref={this.vdoRefs}
src="http://vjs.zencdn.net/v/oceans.mp4"
controls
autoPlay
muted
></video>
<button onClick={this.vdoPause.bind(this)}>暂停</button>
<button onClick={this.vdoPlay.bind(this)}>播放</button>
</div>
);
}
}
// 操作动画
class MyBox extends React.Component {
constructor(props) {
super(props);
this.boxRef = React.createRef();
}
boxExtend() {
const oBox = this.boxRef.current;
oBox.style.width = "500px";
oBox.style.height = "500px";
}
render() {
return (
<>
<div
ref={this.boxRef}
style={{
width: 200 + "px",
height: 200 + "px",
backgroundColor: "orange",
transition: "all 1s",
}}
></div>
<button onClick={this.boxExtend.bind(this)}>Extend</button>
</>
);
}
}
createRef 用法细节
- 通过
createRef
创建ref
对象 - 通过元素的
ref
属性可以附加到React
元素上 - 一般通过构造器中给
this
赋值一个ref
,方便整个组件使用 -
ref
只要传递React
元素中,就可以利用ref
的current
属性访问到该真实DOM
节点 - ref 在
componentDidMount
和componentDidUpdate
触发前更新
ref
不同的使用方式:
-
ref
放在HTML
元素上,则指向真实DOM
节点 -
ref
放在class
组件上,则指向组件实例
<MyBox ref={xxx}/>
- ref 放在函数组件上,不能增加
ref
属性,可以使用React.useRef()
forwardRef (v16.3 以上版本)
将子组件的 ref
暴露给父组件
React.forwardRef((props, ref) => { return React 元素})
const MyInput = React.forwardRef((props, ref) => (
// ref 参数只能在,用 forwardRef 定义的组件内可接收
<input type="text" placeholder={props.placeholder} ref={ref} />
));
class App extends React.Component {
constructor(props) {
super(props);
this.myInputRef = React.createRef();
}
inputOperate() {
this.myInputRef.current.value = "";
this.myInputRef.current.focus();
}
render() {
return (
<div>
<MyInput placeholder="请输入" ref={this.myInputRef} />
<button onClick={this.inputOperate.bind(this)}>获取焦点</button>
{/* <MyVideo /> */}
{/* <MyBox ref={xxx}/> */}
</div>
);
}
}
// 高阶组件 ref 转发
class MyInput extends React.Component {
render() {
return <input type="text" placeholder={this.props.placeholder} />;
}
}
function InputHoc(WarpperComponent) {
class Input extends React.Component {
render() {
const { forwardRef, ...props } = this.props;
return <WarpperComponent ref={forwardRef} {...props} />;
}
}
function forwardRef(props, ref) {
return <Input forwardRef={ref} {...props} />;
}
// 设置别名
forwardRef.displayName = `Input - ${WarpperComponent.name}`;
return React.forwardRef(forwardRef);
// return React.forwardRef((props, ref) => (
// <Input forwardRef={ref} {...props} />
// ));
}
const MyInputHoc = InputHoc(MyInput);
class App extends React.Component {
constructor(props) {
super(props);
this.myInputRef = React.createRef();
}
componentDidMount() {
console.log(this.myInputRef);
}
inputOperate() {
this.myInputRef.current.value = "";
this.myInputRef.current.focus();
}
render() {
return (
<>
<MyInputHoc ref={this.myInputRef} placeholder="请输入" />
<button onClick={this.inputOperate.bind(this)}>获取焦点</button>
</>
);
}
}
Refs 转发(v16.2 及以下)
- 通过 props 转发
class MyInput extends React.Component {
render() {
return <input type="text" ref={this.props.inputRef} />;
}
}
// 通过 props 转发
class App extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
console.log(this.inputRef);
}
render() {
return (
<div>
<MyInput inputRef={this.inputRef} />
</div>
);
}
}
- 回调 Refs
class App extends React.Component {
constructor(props) {
super(props);
this.inputRef = null;
}
setMyInput(el) {
this.inputRef = el;
}
focusInput() {
this.inputRef.value = "";
this.inputRef.focus();
}
render() {
return (
<div>
<input type="text" ref={this.setMyInput.bind(this)} />
<button onClick={this.focusInput.bind(this)}>click</button>
</div>
);
}
}
- 字符串
refs
(不建议使用)
- 组件实例下面的
refs
集合里的ref
- 需要 React 保持跟踪当前正在渲染的组件,
this
没法确定 - React 获取
ref
可能会比较慢 - 不能在 render 中工作
- 不能组合,只能设置一个
ref
class App extends React.Component {
componentDidMount() {
// 字符串 refs
console.log(this.refs.inputRef);
}
render() {
console.log(this.refs.inputRef); // undefined
return (
<div>
<input type='text' ref='inputRef' />
</div>
);
}
}