[React04|青训营笔记]

60 阅读4分钟

3.2 useRef

使用useRef来获取某个组件或元素,返回一个可变的 ref 对象。

ref就是一个类似id的属性,用于获取dom元素

本质上,useRef就是一个其.current属性保存着一个可变值“盒子”.

3.21 Refs and the DOM

ref提供了一种方法允许我们访问DOM节点或在render方法中创建的React元素

作用:提供一种不同于props的方式,在典型数据流之外强制修改子组件。

三种用法:

  • String类型(已过时)
  • 回调函数
  • React.createRef()

String类型的ref有什么问题?

  • 需要React追踪当前呈现的组件(不能猜测this),使React变慢。
  • 并不按照大多数人期待的“渲染回调模式”来运行,因为ref会被放置在 DataGrid上由于以上原因。

渲染回调模式(React Render Callback Pattern):

将this.props.children当做函数来调用。

数据表格(DataGrid)

  • 不可组合(composable)。

何时使用

避免使用refs来做任何可以通过声明式实现来完成的事情。

  • 管理焦点,文本选择或媒体播放
  • 触发强制动画
  • 集成第三方DOM库

创建Refs

通过ref属性附加到React元素

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();//创建
  }
  render() {
    return <div ref={this.myRef} />;//放进ref属性中
  }
}

访问Refs

被传递给render中元素时,可以在ref的current属性中被访问。

const node =this.myRef.current

注意:不能在函数组件上使用ref属性,因为他们没有实例。

但可以在函数组件内部使用ref属性,只要它指向一个DOM元素或class组件。

function CustomTextInput(props){
//必须声明 textInput  ref才可以引用它
    const textInput=useRef(null);
    function handleClick(){
       textInput.current.focus();
  }
  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

回调Refs

可以更精细地控制何时refs被设置和接触。

不同于createRef()创建的ref属性,通过回调ref会传递一个函数。

这个函数接受react组件实例或HTML DOM元素作为参数,使他们能在其他地方被存储和访问。

例子:使用ref回调函数,在实例的属性中存储对DOM节点的引用。

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
​
    this.textInput = null;
​
    this.setTextInputRef = element => {
      this.textInput = element;
    };
​
    this.focusTextInput = () => {
      // 使用原生 DOM API 使 text 输入框获得焦点
      if (this.textInput) this.textInput.focus();
    };
  }
​
  componentDidMount() {
    // 组件挂载后,让文本框自动获得焦点
    this.focusTextInput();
  }
​
  render() {
    // 使用 `ref` 的回调函数将 text 输入框 DOM 节点的引用存储到 React
    // 实例上(比如 this.textInput)
    return (
      <div>
        <input
          type="text"
          ref={this.setTextInputRef}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

React在组件挂载时,会调用ref回调函数并传入DOM元素,当卸载时调用它并传入null。

在componentDidMount或componentDidUpdate触发前,React会保证refs一定是最新的。

import {useRef} from 'react'function App5(){
    const element = useRef(null)
​
    const handleClick = () => {
        console.log(element.current.)           // 获取input
        console.log(element.current.value)  // 获取到input中的值
        
    }
    return (
        <>
            <input type="text" ref={element} />
            <button onClick={handleClick}>获取input标签</button>
        </>
    )
}
​
export default App5;

3.3 memo

React 中当组件的 props 或 state 变化时,会重新渲染,实际开发会遇到不必要的渲染场景。

父组件更新时,子组件被迫更新,会造成性能损耗,此时需要用memo来缓存子组件,避免被迫更新

import React, {useState} from 'react'// 子组件
function Sub(){
    console.log('子组件被更新了')
    return <div>子组件</div>
}
​
// 父组件
export default function App(){
    const [msg, setMsg] = useState("你好世界");
    return (
        <>
            <h2>内容为:{msg}</h2>
            <button onClick={()=>setMsg("Hello World")}>修改Msg</button>
            <hr />
            <Sub />
        </>
    )
}

用memo包裹住子组件即可

const Sub = memo(() => {
    console.log('子组件被更新了')
    return <div>子组件</div>
})

注意,此处父组件只是简单调用子组件,并未给子组件传递任何属性

如果父组件的某个属性给子组件通过props传了值呢?

3.4 useCallback与useMemo

The useCallback and useMemo Hooks are similar. The main difference is that useMemo returns a memoized value and useCallback returns a memoized function.

一个返回值,一个返回函数。

useCallback示例

const doSth=useCallback(()=>{setNum(num=>num+1)
  },[])//useCallback里丢进函数 第二个参数丢一个空数组代表不检测更新

3.41useCallback基础用法

与useState用法基本一致,但最后会返回一个函数,用一个变量保存起来。

返回的函数a会根据b的变化而变化,如果b始终未发生变化,a也不会生成,避免在不必要的情况下更新

情景:通过属性传递给子组件

比如一个父组件中

const a = useCallback(() => {
    return function() {
        console.log(b)
    }
},[b])
console.log(a)
console.log(a())
  • 第一种用法:父子组件函数式传参 子组件受到的参数不变(空数组),自然不会更新,从而减少了组件间不必要的更新

3.42 useMemo

与useCallback差不多,只是useMemo需要再套一个函数

const mySetMsg = useCallback(() => setMsg(()=>"Hello World"), [])   
//注意useMemo
​
const mySetMsg = useMemo(()=>{
  return () => setMsg("Hello World")
}, [])