useRef使用场景
- 获取子组件或 DOM节点的句柄
- 同步渲染不同周期所共享的的数据
- 渲染周期之间共享数据的存储
- 定时器
- 拖拽
- 事件,鼠标移动
- 第三方组件,echarts.js, d3.js
- useRef 不能被函数组件使用
- 函数组件不能100% 代替类组件
useRef可以“跨渲染周期”保存数据,只会创建一次,不会多次创建
createRef会多次创建
state 跨渲染周期,也就是在组件被多次渲染之后依旧不变的属性?
一个组件的state可以在多次渲染之后依旧不变。但是,state的问题在于一旦修改了它就会造成组件的重新渲染
用useRef来跨越渲染周期存储数据,而且对useRef修改也不会引起组件渲染
用 ref对象的current属性来存储定时器的ID,可以在多次渲染之后依旧保存定时器ID,从而能正常清除定时器
ref.current
https://juejin.cn/post/6972850126666596383
class
class App {it = 0}
hooks
function App () {const it = useRef(0)}
forwardRef
ref & forwardRef
https://blog.csdn.net/qq_34086980/article/details/104791790
import React, { createRef, useImperativeHandle, forwardRef } from "react"// 父组件class Parent extends React.Component {constructor() {super()this.ref = createRef()}componentDidMount() {this.ref.current.alert()}render() {return <ForwardFunctionChild ref={this.ref} />}}export default Parent// 子组件接收 props & reffunction FunctionChild(props, ref) {useImperativeHandle(ref, () => ({alert() {alert("This is function component")}}))return <span>This is function child</span>}const ForwardFunctionChild = forwardRef(FunctionChild)
createRef
- class组件 React.createRef() ```jsx import React, { createRef } from “react”
// 父组件 class Parent extends React.Component { constructor() { super() this.ref = createRef() }
componentDidMount() { // 调用子组件的方法 this.ref.current.alert() }
render() {
return
export default Parent
// 子组件 class ClassChild extends React.Component { alert() { alert(“this is class child”) } render() { return This is class child } }
<a name="557b9fb0"></a>## ref函数子组件1. 函数式组件无法获取ref,重复踩坑2. ref获取到的是子组件的实例对象,函数式没有this属性,获取为 undefined1. **利用回调函数**达到赋值操作2. 函数式子组件,打印 ref一直是 undefined3. [https://blog.csdn.net/weixin_33971977/article/details/86027673](https://blog.csdn.net/weixin_33971977/article/details/86027673)<a name="6n12r"></a>### 函数父组件获取 函数子组件1. useRef```jsx// 父组件import React, { memo, useRef } from 'react'import Form from './Form'function ModalForm (props) {const fileRef = useRef(null)const formRef = useRef(null)function onValidate () {const form = formRef.currentform.validateFields(err => {if (err) return // 让出错的代码先返回console.log('通过验证', err)})console.log('ref', formRef)}render () {return (<Modal visible={visible}><Form ref={ ref => formRef.current = ref } /><div onClick={() => fileRef.current.click() }><input type="file" hidden ref={fileRef}/></div></Modal>)}}export default memo(ModalForm)// 子组件<Form ref={props.ref}><Form.Item>{ getFieldDecorator('name', {})(<Input />) }</Form.Item></Form>
class父组件获取函数子组件
React.createRef()获取子组件- 通过React.createRef()创建ref,挂载到组件上
- 16.3+ 使用此方法来创建ref,将其赋值给一个变量
- 通过
ref挂载在dom节点或组件上,该ref的current属性将能拿到dom节点或组件的实例
// 父组件import React, { PureComponent, createRef } from 'react'import Form from './Form'class ModalForm extends PureComponent {constructor(props){super(props)this.formRef = createRef()}onValidate = () => {const form = this.formRef.currentform.validateFields(err => {if (err) return // 让出错的代码先返回console.log('通过验证', err)})console.log('ref', this.formRef.current)}render () {return (<Modal visible={visible}><Form ref={this.formRef} /></Modal>)}}
class父组件获取 class子组件
import react,{Component} from 'react'import Child from './child'// parentclass Parent extends Component{onClick = () => {//调用子组件的方法this.child && this.child.onClick()}render(){return(<div>// 把子组件的this指针挂载成父组件的一个变量<Child onRef={ ref => this.child = ref}></Child><button onClick={ this.onClick }>点击</button></div>)}}export default Parent;// childexport default class Child extends Component{constructor(props){super(props)// 如果父组件传来该方法 则调用方法将子组件this指针传过去props.onRef && props.onRef(this)this.state = {value: 100}}onClick =()=>{console.log('父组件调用子组件方法', this.state.value)}render() {return <div><div>}}
注意this指向问题
https://blog.csdn.net/fuhegegnw/article/details/110009760
ref错误
- index.js:2177 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
- Check the render method of
BaseForm. - 修改,connect,withRouter,Form.create()新增 {withRef: true} ```jsx export default Form.create({withRef:true})(BaseForm)
export default connect( stateToProps, null, null, { forwardRef: true } )(BaseForm)
export default withTranslation(‘translation’, { withRef: true })(BaseForm)
4. Form.create {withRef: true}的话,会把这个ref的实例包裹起来,并使之有效5. 引出新的问题:1. index.js:2177 Warning: `withRef` is deprecated, please use `wrappedComponentRef` instead. See: [https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140](https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140)<a name="mtCMr"></a>### ref不能重复2个组件的 ref不能重复,重复会导致后面的覆盖前面的<br /><a name="rbiMJ"></a>### forwardRefforwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?<br />原因:forwardRef会让 stateless组件的defaultProps和propTypes属性失效<br />正确的写法:```jsximport React, {forwardRef} from 'react';const App = forwardRef((props, ref) => {return <div></div>;})App.displayName = 'App';App.defaultPorps = {value: PropTypes.array}export default App;
不推荐的写法,控制台会报警告⚠️
function UserFrom(props, parentRef) {}export default React.forwardRef(UserFrom)
优化的写法,正确额的
function UserFrom(props, parentRef) {}const UserFromRef = React.forwardRef(UserFrom)UserFromRef.propTypes = {onChange: PropTypes.func.isRequired,}export default UserFromRef;
forwardRef参考资料:https://stackoverflow.com/questions/59716140/using-forwardref-with-proptypes-and-eslint
