首先,Hook是什么?

Hook

Hook 是 React 团队在 React 16.8 版本中提出的新特性,在遵循函数式组件的前提下,为已知的 React 概念提供了更直接的 API:props,state,context,refs 以及声明周期,目的在于解决常年以来在 class 组件中存在的各种问题,实现更高效的编写 react 组件。


Hook的使用规则是什么?

Hook 就是 Javascript 函数,使用它们时有两个额外的规则:

函数外层调用 Hook,不要在循环、条件判断或者子函数中调用。
只能在 React 的函数组件和 自定义 Hook


Hook的使用!

useState :

useState只能在 React 的函数组件和自定义 Hook

const [state, setState] = useState(initialState);

Hook 是什么?

useState :方法的使用

代码如下:

import React, { useState } from 'react';

export default function UseState() {
  const [count, setCount] = useState(0);

  return (
    <div>
       {/* 点击按钮 count-1或+1 */}
      <button onClick={() => setCount(count - 1)}>-</button>
      <button onClick={() => setCount(count + 1)}>+</button>
       {/* input发生变化 获取count */}
      <input type="text" value={count} onChange={(e) => setCount(e.target.value)} />
    </div>
  );
}

useEffect:

useEffect 做了什么?

为什么在组件内部调用 useEffect?

useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它。)你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

useEffect () 本身是一个函数,由 React 框架提供,在函数组件内部调用即可。

useEffect(didUpdate);

useEffect 的使用

import React, { useState, useEffect } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  // useEffect 内的回调函数会在初次渲染后和更新完成后执行
  // 相当于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    document.title = `您 单击了 ${count} 次`;
  });

  //这里也可以写成
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]); // 仅在 count 更改时更新

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

useContext :

useContext可以帮助我们跨越组件层级直接传递变量,实现数据共享。

const value = useContext(MyContext);

useContext 的使用

父组件写入

import React,{useEffect,useState,useRef,createRef} from 'react'
import {ThemeContext,ThemeContext2} from './context'
import A3 from './components/A3'

function A2(props) {
  return (
    <div><A3 /></div>
  )
}

//父子传值
function A1(props) {
    const [x1,setX1]=useState('小蓝')

    return (
        <ThemeContext2.Provider value={{title1:x1}}>
            <A2 />
        </ThemeContext2.Provider>
    )
  }

export default function Context(props){
    const [name,setName]=useState("小白");

    const fn=opt=>{
        // console.log(opt,'opt')
    }

    return (
        <ThemeContext.Provider value={{title:'小花'}}>
            <A1
                x2={fn}
            />
        </ThemeContext.Provider>
    )
}

context页面

import React from "react";
// createContext 创建 Context 对象
export const ThemeContext =React.createContext();
export const ThemeContext2 =React.createContext();

子组件 A3页面:

import React,{useContext} from 'react'
import {ThemeContext,ThemeContext2} from '../context'

export default function A3 (props){
    const values=useContext(ThemeContext);
    const values2=useContext(ThemeContext2);

    return (
        <>
            <h2>A1: {values.title}</h2>
            <h2>A3:{values2.title1}</h2>
        </>
    )
}

子组件 Acontext页面

import React,{useContext} from 'react'
import {ThemeContext} from '../context'

export default function Acontext (props){
    const values=useContext(ThemeContext);
    const {xxx}=props
    return (
        <>
            <h1>A3:{xxx}</h1>
            <h2>A3:{values.title}</h2>
        </>
    )
}

useMemo :

useMemo接收两个参数,分别是函数和一个数组(实际上是依赖),函数里return 函数,数组内存放依赖

useMemo的使用:

import React, { useState, useMemo } from 'react';

function counterText({ countInfo }) {
  return (
    <p>{countInfo.name}: {countInfo.number}</p>
  );
}
// // 使用 React.memo 检查 props 变更,复用最近一次渲染结果
const CounterText = React.memo(counterText);

export default function Counter() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  const countInfo1 = {
    name: 'count1',
    number: count1
  };
  // 使用 useMemo 缓存最近一次计算结果,会在依赖项改变时才重新计算
  const countInfo2 = useMemo(() => ({
    name: 'count2',
    number: count2
  }), [count2]);

  return (
    <>
      <div>
        <CounterText countInfo={countInfo1} />
        <button onClick={() => setCount1(count1 + 1)}>Add count1</button>
      </div>
      <div>
        <CounterText countInfo={countInfo2} />
        <button onClick={() => setCount2(count2 + 1)}>Add count2</button>
      </div>
    </>
  );
}

useCallBack :

是为了缓存方法。我们可以通过自定义hooks函数来使用一下useCallback,我们可以通过自定义hooks函数来实现一个获取窗口大小的函数。

useCallback的使用:

import React, { ReactElement, useCallback, useState } from "react";

const Example = () => {
  const [n, setN] = useState<number>(0);
  const [m, setM] = useState<number>(10);
  console.log("执行最外层盒子了");

  const addN = useCallback(() => {
    setN(n + 1);
  }, [n]);

  const addM = useCallback(() => {
    setM(m + 1);
  }, [m]);
  return (
    <div style={{ textAlign: "center", marginTop: 50 }}>
      最外层盒子
      <Child1 value={n} onClick={addN} />
      <Child2 value={m} onClick={addM} />
      <button onClick={addN}>n+1</button>
      <button onClick={addM}>m+1</button>
    </div>
  );
};

interface childProp {
  value: number;
  onClick?: () => void;
}

const Child1 = React.memo((props: childProp): ReactElement<childProp> => {
  console.log("执行子组件1了");
  return <div>子组件1上的n:{props.value}</div>;
});

const Child2 = React.memo((props: childProp): ReactElement<childProp> => {
  console.log("执行子组件2了");
  return <div>子组件2上的m:{props.value}</div>;
});

export default Example;

useRef:

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

useRef 的使用:

import React, { useRef } from "react";
export default function App() {
  const r = useRef(0);
  console.log(r);
  const add = () => {
    r.current += 1;
    console.log(`r.current:${r.current}`);
  };
  return (
    <div className="App">
      <h1>r的current:{r.current}</h1>
      <button onClick={add}>点击+1</button>
    </div>
  );
}

useReducer:

使用useReducer接收Reducer函数和一个初始state,并返回当前值state与dispatch函数,并且当触发事件时,使用dispatch传递action,让reducer计算出新的state

可以让你通过 reducer 来管理组件本地的复杂 state。
Reducers 非常便于单独测试,且易于扩展,以表达复杂的更新逻辑。如有必要,您可以将它们分成更小的 reducer。

export default function App() {
  const initialState = { n: 1 };
  const [state, dispatch] = useReducer(reducer, initialState); 
//使用useReducer接收reducer参数和初始state
  return (
    <>
      <div>{state.n}</div>
      <button
        onClick={() => {
          dispatch({ type: "add" });  // 传递action
        }}
      >
        点击+
      </button>
      <button
        onClick={() => {
          dispatch({ type: "sub" });//传递action触发reducer函数
        }}
      >
        点击-
      </button>
    </>
  );
}