常用Hook

120 阅读3分钟

Hook

  • 只能在函数式组件内的顶层调用

useState

在函数式组件中实现响应式数据

import React,{useState} from 'react'

export default function StateDemo() {
  let [num,setNum] = useState(100) //num是响应式数据,默认值是100,setNum是触发num响应式变化的方法
  return (
    <div>
      <h1>演示useState的使用:{num}</h1>
      <button onClick={()=>{
        setNum(++num)
      }}>按钮</button>
    </div>
  )
}

useEffect 【必须传两个参数】

副作用函数 (附带的作用) 在函数式组件中,实现跟生命周期一样的效果

useEffect(()=>{
    console.log('扮演componentDidMount的角色');
    todoGet().then(res=>{
      setTodos(res.data.results)
    })
  },[])  //此处如果不写空数组,这个useEffect会在所有响应式数据发生更新时反复触发

  useEffect(()=>{
    console.log('扮演componentDidUpdate');
  },[num])  //此处写了 就在改num改变时修改

useRef

作用跟类组件中 createRef 相同

import React, { useRef } from "react";
import { useEffect } from "react";

export default function RefDemo() {
  let inputRef = useRef(); //1.定义
  // console.log(inputRef); //3.能获取input元素?
  useEffect(() => {
    console.log(inputRef); //3.能获取input元素?
    inputRef.current.focus();
  }, []);
  return (
    <div>
      02-useRefDemo
      {/* 2.绑定 */}
      <input type="text" ref={inputRef} />
    </div>
  );
}

性能优化(useMemo、useCallback)

  • 我们在使用 React 开发过程中经常会遇到父组件引入子组件的情况,在不做任何优化处理的时候,往往会造成子组件不必要的重复渲染。看下面一个简单的例子
// 例子1:这种情况下,每次父组件更新count值的时候,子组件也会重复渲染

function Child(props) {
  console.log("子组件渲染");
  return <div>{props.title}</div>;
}
function Parent() {
  const [count, setCount] = useState(1);
  return (
    <div>
      <Child title="我是子组件" />
      <button onClick={() => setCount(count + 1)}>add</button>
      <div>count:{count}</div>
    </div>
  );
}

React.memo

  • React.memo 为高阶组件,它和 React.PureComponent 挺相似的
  • 用法:React.memo(component, Func),第一个参数是自定义组件,第二个参数是一个函数,用来判断组件需不需要重新渲染。如果省略第二个参数,默认会对该组件的 props 进行浅比较
// 改造例子1:这种情况下,Child的props经浅比较无变化,则不重复渲染
function Child(props) {
  console.log("子组件渲染");
  return <div>{props.title}</div>;
}
const NewChild = React.memo(Child, (prevProps, nextProps) => {
  // 自定义对比方法,也可忽略不写
  // return true 则不重新渲染
  // return false 重新渲染
});
function Parent() {
  const [count, setCount] = useState(1);
  return (
    <div>
      <NewChild title="我是子组件" />
      <button onClick={() => setCount(count + 1)}>add</button>
      <div>count:{count}</div>
    </div>
  );
}
  • 然而在某些情况下,光靠 React.memo 包裹子组件,子组件还是会进行不必要的重复渲染更新,这时 useMemo 和 useCallback 则可以进行更细粒度的性能优化。看以下这个例子
// 例子2
function Child({title, onChangeTitle}){
  console.log('子组件渲染')
  return(
      <>
        <div>{title.value}</div>
        <button onClick={() => onChangeTitle('我是新的title')}>change title</button>
      </>
  )
}
const NewChild = React.memo(Child);

function Parent(){
    const [count, setCount] = useState(1);
    const [title, setTitle] = useState('我是子组件');
    const onChangeTitle = (text) => {
        setTitle(text)
    }
    return(
        <div>
            <NewChild title={{value: title}} onChangeTitle={onChangeTitle}>
            <button onClick={() => setCount(count+1)}>add</button>
            <div>count:{count}</div>
        </div>
    )
}

useMemo

  • 第一次渲染时执行,缓存变量,之后只有在依赖项改变时才会重新计算记忆值

useCallback

  • 第一次渲染时执行,缓存函数,之后只有在依赖项改变时才会更新缓存
//改造例子2
function Child({title, onChangeTitle}){
  console.log('子组件渲染')
  return(
      <>
        <div>{title.value}</div>
        <button onClick={() => onChangeTitle('我是新的title')}>change title</button>
      </>
  )
}
const NewChild = React.memo(Child);

function Parent(){
  const [count, setCount] = useState(1);
  const [title, setTitle] = useState('我是子组件');
  const onChangeTitle = useCallback((text) => {
      setTitle(text)
  },[])
  const memoTitle = useMemo(() => ({value: title}), [title])
  return(
      <div>
          <NewChild title={memoTitle} onChangeTitle={onChangeTitle} />
          <button onClick={() => setCount(count+1)}>add</button>
          <div>count:{count}</div>
      </div>
  )
}
  • useMemo 和 useCallback 用法差不多,都是在第一次渲染的时候执行,然后在依赖项改变时再次执行,不同点在于,useMemo返回缓存的变量useCallback返回缓存的函数