一、组件类的缺点

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加:

import React, { useState } from 'react';

function Example() {
  // 声明一个新的叫做 “count” 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

官方解读:
1: 引入 React 中的 useState Hook。它让我们在函数组件中存储内部 state。
2: 在 Example 组件内部,我们通过调用 useState Hook 声明了一个新的 state 变量。它返回一对值给到我们命名的变量上。我们把变量命名为 count,因为它存储的是点击次数。我们通过传 0 作为 useState 唯一的参数来将其初始化为 0。第二个返回的值本身就是一个函数。它让我们可以更新 count 的值,所以我们叫它 setCount。
3: 当用户点击按钮后,我们传递一个新的值给 setCount。React 会重新渲染 Example 组件,并把最新的 count 传给它。

import React, { Component } from "react";

export default class Button extends Component {
  constructor() {
    super();
    this.state = { buttonText: "Click me, please" };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(() => {
      return { buttonText: "Thanks, been clicked!" };
    });
  }
  render() {
    const { buttonText } = this.state;
    return <button onClick={this.handleClick}>{buttonText}</button>;
  }
}

这个组件类仅仅是一个按钮,但可以看到,它的代码已经很"重"了。真实的 React App 由多个类按照层级,一层层构成,复杂度成倍增长。再加入 Redux,就变得更复杂。

  • 大型组件很难拆分和重构,也很难测试。
  • 业务逻辑分散在组件的各个方法之中,导致重复逻辑或关联逻辑。
  • 组件类引入了复杂的编程模式,比如 render props 和高阶组件。

二、函数组件

React 团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。 组件的最佳写法应该是函数,而不是类。
不过之前的版本中函数定义组件

    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }

但是,这种写法有重大限制,必须是纯函数,不能包含状态,也不支持生命周期方法,因此无法取代类。React Hooks 的设计目的,就是加强版函数组件,完全不使用"类",就能写出一个全功能的组件。也就是函数组件可以像类组件一样使用。

纯函数

三、Hook

Hook 这个单词的意思是"钩子"。
Hook 是什么? Hook 是一个特殊的函数,它可以让你“钩入” React 的特性

Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:

  1. 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  2. 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook )
  • useState()
  • useContext()
  • useReducer()
  • useEffect()

四 常用hooks

1. useState 状态钩子

useState()这个函数接受状态的初始值,作为参数,该函数返回一个数组,数组的第一个成员是一个变量,指向状态的当前值。第二个成员是一个函数,用来更新状态,约定是set前缀加上状态的变量名。这个初始 state 参数只有在第一次渲染时会被用到
tips

  1. setState的值需要是新值(新的地址
  2. 一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。

    setObj(Object.assign(obj, { name: 'lisi' }))
    setObj({...obj, name: 'lisi})
      会发现值没有变 因为地址没变 assign只是在原来地址合并。

    setState的值需要是新值,可以接受一个函数作为参数 函数的返回值需要是新值

    import React, { useState } from 'react';
    
     const App =  () => {
      const [arr, setArr] = useState([1,2,3]);
      return (
     <div>
       <button onClick={() => setArr(arg => {
         arr.push(4)
         console.log(arr === arr);
         // return arr 这样不改变 需要新的arr
         return [...arr]
       })}>
         Click me
       </button>
       <h2>{arr}</h2>
     </div>
      );
    }
    export default App;

    useState值为函数时,函数的返回值为初始值。

import React, { useState } from 'react';

 const App =  () => {
  const [func, setFunc] = useState(()=>({name: 'lisi'}));
  return (
    <div>
      <button onClick={() => setFunc({name: 'pp'})}>
        change-name
      </button>
      {/*  Objects are not valid as a React child  */}
      {/* <h2>{func}</h2> */}
      <h2>{func.name}</h2>
    </div>
  );
}
export default App;

2. useEffect 副作用钩子

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途

语法:

     useEffect(()  =>  {
      // Async Action
    }, [dependencies])

useEffect()接受两个参数。第一个参数是一个函数,异步操作的代码放在里面。第二个参数是一个数组,用于给出 Effect 的依赖项,只要这个数组发生变化,useEffect()就会执行。第二个参数可以省略,这时每次组件渲染时,就会执行useEffect()。副作用函数还可以通过返回一个函数来指定如何“清除”副作用。

解答:
参数2不写,默认是监视所有状态,只要有状态改变都会执行
参数2为空数组, 不监视任何状态,谁变化也不执行,但是第一次渲染是会执行的
参数2填写,监听改状态

例子:

tips

  • 副作用函数需要在组件内声明,它们可以访问到组件的 props 和 state(闭包)。
  • 无阻塞更新

获取数据可以在组件挂载前后获取,而effect是挂载后获取,这就表明数据就算请求出错,但是组件已经挂载结束,数据请求失败不会影响界面。

  • 可以有多个useEffect

3. useReducer action 钩子

  • React 本身不提供状态管理功能,通常需要使用外部库。这方面最常用的库是 Redux。
  • Redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态,Reducer 函数的形式是(state, action) => newState。
  • useReducers()钩子用来引入 Reducer 功能。
    语法

它接受 Reducer 函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action 的dispatch函数。

4. useContext 共享状态钩子

5. useRef

五、创建自己的 Hooks

03-05 16:05