hooks + 函数组件
实质: 使用函数组件+hook 来实现 类组件的功能
官方期望用函数组件+hook 逐步代替类组件
为什么要代替类组件?
- 降低 react 的入门门槛,增加开发者数量
- 降低开发难度
- 函数式编程
函数组件
- 函数组件就是一个函数
- 函数组件由两个参数\
- props 就是绑定在 App 组件身上的 props
- ref ref 绑定,用于获取内容
 
- 函数组件特点
- this 为 undefined
- 如果只使用函数组件,那么 react 的很多特性都不可以使用了,比如: state \ setState \ forceUpdate \contextType \ 生命周期 。。。
 
| 12
 3
 4
 5
 
 | interface P {}const App = (props: P, ref: any) => {
 return <div> App </div>;
 };
 export default App;
 
 | 
Hook 钩子函数
- react 16.8 版本之后才提供了一个新的特性:Hook
- Hook + 函数组件才能实现 react 的特性
Hook
官方提供了 10 个内置 Hook
useState(initValue) // initValue 初始值
用于函数组件定义 state,和修改 state 的方法
- 定义格式: const [stateName,setStateName] = useState<数据类型>( 初始值 ) 
- 比如: const [name,setName] = useState(‘lakers’) 
- 注意点 - 
- 基础数据类型: 直接赋值 | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import React, { useState } from "react";
 export default function App() {
 const [name, setName] = useState<string>("yyc");
 return (
 <div>
 <button
 onClick={() => {
 setName("yyc2");
 }}
 >
 修改名字
 </button>
 <p>{name}</p>
 </div>
 );
 }
 
 |  
 
- 引用数据类型,解构赋值给它 | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 | import React, { useState } from "react";
 interface People {
 name: string;
 }
 
 export default function App() {
 const [people, setPeople] = useState<People>({
 name: "fox",
 });
 
 const [arr, setArr] = useState<unknown[]>([1, 2, 3, 4]);
 const changeName = () => {
 
 
 
 
 
 setPeople({
 name: "dog",
 });
 
 
 };
 
 const add = () => {
 arr.push(arr.length + 1);
 setArr([...arr]);
 };
 return (
 <div>
 <button onClick={changeName}>修改名字</button>
 <p>{people.name}</p>
 <button onClick={add}>增加</button>
 <ul>
 {arr.map((item, index) => (
 <li key={index}> {item} </li>
 ))}
 </ul>
 </div>
 );
 }
 
 |  
 
 
useEffect
useEffect 可以让函数组件实现类组件部分生命周期的功能
可以实现以下几个生命周期钩子函数的功能
-  componentDidMount
-  componentDidUpdate [ 属性或者状态的监听 ]
-  componentWillUnmount
-  useEffect(回调函数,依赖项)
- 有返回值,而且返回值是一个函数,—–> 相当于 componentWillUnmount
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | import React from "react";
 import Hello from "./Hello";
 
 export default function App() {
 const [flag, setFlag] = React.useState<boolean>(true);
 return (
 <div>
 <button
 onClick={() => {
 setFlag(false);
 }}
 >
 {" "}
 销毁{" "}
 </button>
 {flag && <Hello />}
 </div>
 );
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | import { time } from "console";
 import React, { useEffect } from "react";
 
 export default function Hello() {
 let timer: any = null;
 useEffect(() => {
 console.log("创建了");
 
 timer = setInterval(() => {
 console.log("1111");
 }, 1000);
 }, []);
 useEffect(() => {
 return () => {
 console.log("销毁了");
 
 clearInterval(timer);
 };
 });
 return <div>hello</div>;
 }
 
 | 
- 依赖项就是一个数组
- 可以是空数组 —–> 相当于 componentDidMount
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | import React, { useEffect } from "react";
 export default function App() {
 useEffect(() => {
 
 console.log("mount");
 
 const pTxt: any = document.querySelector("p");
 pTxt.style.background = "pink";
 
 
 }, []);
 return (
 <div>
 <p>123</p>
 </div>
 );
 }
 
 | 
- 数组中也可以放 state 或者 props ——> componentDidUpdate
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | import React, { useEffect, useState } from "react";
 export default function App() {
 const [count, setCount] = useState<number>(0);
 useEffect(() => {
 console.log("执行");
 }, [count]);
 return (
 <div>
 <button
 onClick={() => {
 setCount((pre) => pre + 1);
 }}
 >
 按钮
 </button>
 <p>{count}</p>
 </div>
 );
 }
 
 | 
useContext
- 新建 context 文件夹/index.ts 文件
| 12
 3
 4
 5
 6
 
 | import React, { createContext } from "react";
 
 const ctx = createContext(0);
 
 export default ctx;
 
 | 
- 用 ctx.Provider 包裹
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | import React, { useState } from "react";import Father from "./components/Father";
 import ctx from "./context";
 
 export default function App() {
 const [money] = useState<number>(200000);
 return (
 <div>
 <h3> useContext -- 跨组件通信 </h3>
 <ctx.Provider value={money}>
 <Father />
 </ctx.Provider>
 </div>
 );
 }
 
 | 
- 子组件用 useContext 来接收
| 12
 3
 4
 5
 6
 7
 
 | import React, { useContext } from "react";import ctx from "../context";
 
 export default function GrandSon() {
 const money = useContext(ctx);
 return <div>{money}</div>;
 }
 
 | 
useRef + useImperativeHandle
- 可以绑定元素
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | import React, { useRef } from "react";
 export default function App() {
 const pRef: any = useRef(null);
 const setBgc = () => {
 
 pRef.current.style.background = "pink";
 };
 return (
 <div>
 <button onClick={setBgc}>按钮</button>
 <p ref={pRef}>123</p>
 </div>
 );
 }
 
 | 
- 可以绑定类组件(计数案例)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import React, { useRef } from "react";
 import Hello from "./Hello";
 
 export default function App() {
 const helloRef: any = useRef(null);
 const addVal = () => {
 helloRef.current.add();
 };
 return (
 <div>
 <button onClick={addVal}>+</button>
 <Hello ref={helloRef} />
 </div>
 );
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | import React, { Component } from "react";
 
 interface P {}
 
 interface S {
 count: number;
 }
 export default class Hello extends Component<P, S> {
 constructor(props: P) {
 super(props);
 this.state = {
 count: 0,
 };
 }
 add = () => {
 this.setState({
 count: this.state.count + 1,
 });
 };
 render() {
 const { count } = this.state;
 return (
 <div>
 <p> {count} </p>
 </div>
 );
 }
 }
 
 | 
- 不可以绑定函数组件(解决:使用 React.forwardRef + useImperativeHandle)
- useImperativeHandle(ref,()=>{})
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import React, { useRef } from "react";
 import Hello from "./Hello";
 
 export default function App() {
 const helloRef: any = useRef(null);
 const addVal = () => {
 helloRef.current.add();
 };
 return (
 <div>
 <button onClick={addVal}>+</button>
 <Hello ref={helloRef} />
 </div>
 );
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | import React, { useState, useImperativeHandle } from "react";
 
 function Hello(props: any, ref: any) {
 const [count, setCount] = useState<number>(0);
 const add = () => {
 setCount((pre) => {
 return pre + 1;
 });
 };
 useImperativeHandle(
 ref,
 () => {
 
 return {
 add,
 };
 }
 );
 return (
 <div>
 <p>{count}</p>
 </div>
 );
 }
 
 export default React.forwardRef(Hello);
 
 | 
useReducer
- 用于定义状态,修改状态,和 useState 相似
| 12
 3
 
 | const [state, dispatch] = useReducer(reducer, initialState);
 
 
 | 
案例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | import React, { useReducer } from "react";
 const initialState = {
 count: 0,
 };
 
 const reducer = (state: any, action: any) => {
 switch (action.type) {
 case "in":
 return { count: state.count + 1 };
 case "de":
 return { count: state.count - 1 };
 default:
 throw new Error();
 }
 };
 
 export default function App() {
 const [state, dispatch] = useReducer(reducer, initialState);
 return (
 <div>
 <button
 onClick={() => {
 dispatch({
 type: "in",
 });
 }}
 >
 +
 </button>
 <hr />
 <button
 onClick={() => {
 dispatch({
 type: "de",
 });
 }}
 >
 -
 </button>
 <p>{state.count}</p>
 </div>
 );
 }
 
 | 
hooks 中用于渲染优化的(useMemo/useCallback)
- useMemo(返回的是一个记忆值,直接用)
- 参数(callback,array) 第一个为函数方法,第二个为数组 填依赖项
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | import React, { useState, useMemo } from "react";
 export default function App() {
 const [count, setCount] = useState<number>(0);
 const [list] = useState<number[]>([1, 2, 3, 4]);
 const add = () => {
 setCount((pre) => pre + 1);
 };
 const renderList = () => {
 console.log("chufale");
 return list.map((item, index) => <li key={index}> {item} </li>);
 };
 
 
 
 const memoList = useMemo(renderList, [list]);
 return (
 <div>
 <button onClick={add}>+</button>
 <p>{count}</p>
 {}
 这里出现的问题 点击增加会重新渲染list列表
 <br />
 解决办法:useMemo
 {memoList}
 </div>
 );
 }
 
 | 
- useCallback(callback,array) 用法和 useMemo 一样
- 
- useCallback 返回值是一个记忆函数
 
- 
- 这个记忆函数必须传递给子组件用
 
- 
- 这个子组件必须是 React.memo() 的参数
 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | import React, { useState, useCallback } from "react";
 import Hello from "./Hello";
 
 export default function App() {
 const [count, setCount] = useState<number>(0);
 const [list] = useState<number[]>([1, 2, 3, 4]);
 const add = () => {
 setCount((pre) => pre + 1);
 };
 const renderList = () => {
 console.log("chufale");
 return list.map((item, index) => <li key={index}> {item} </li>);
 };
 
 const callbackList = useCallback(renderList, [list]);
 return (
 <div>
 <button onClick={add}>+</button>
 <p>{count}</p>
 {}
 这里出现的问题 点击增加会重新渲染list列表
 <br />
 解决办法:useCallback
 <Hello callbackList={callbackList} />
 </div>
 );
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | import React, { memo, ReactNode } from "react";
 
 interface P {
 callbackList: () => ReactNode;
 }
 function Hello(props: P) {
 return (
 <div>
 <ul>{props.callbackList()}</ul>
 </div>
 );
 }
 
 export default memo(Hello);
 
 | 
useLayoutEffect 用法和 useEffect 一致
useDebugValue
自定义 HOOK 封装
- 封装一个函数,只不过这个函数有些特别【useState,useEffect】
- 自定义 Hook 名称
- 其他 hooks 封装: