1

一、组件类的缺点

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 传给它。

注意
React 16.8.0 是第一个支持 Hook 的版本。升级时,请注意更新所有的 package,包括 React DOM。 React Native 从 0.59 版本开始支持 Hook
v16.8 版本之前,组件的标准写法是类(class)。下面是一个简单的组件类。
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,就变得更复杂。

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

二、函数组件

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

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

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

纯函数

三、Hook

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

React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。你需要什么功能,就使用什么钩子。React 默认提供了一些常用钩子,你也可以封装自己的钩子。所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用use前缀命名,便于识别。你要使用 xxx 功能,钩子就命名为 usexxx。

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

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

四 常用hooks

1. useState 状态钩子

useState() 通过在函数组件里调用它来给组件添加一些内部 state。纯函数不能有状态,所以把状态放在钩子里面。
语法 const [obj, setObj] = useState({name:'zs'});

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()用来引入具有副作用的操作
在 React 组件中执行 数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用

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 功能。
    语法

    const [state, dispatch] = useReducer(reducer, initialState);

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

4. useContext 共享状态钩子

如果需要在组件之间共享状态,可以使用useContext()。

5. useRef

作用1 获取dom
作用2 保存变量

五、创建自己的 Hooks


小懵
4 声望0 粉丝

« 上一篇
React
下一篇 »
typescript