react的Hooks介绍

Hooks

一.Hook简介

Hook是React 16.8新增的特性.它可以让你在不编写class的情况下使用state以及生命周期等特性
之前了解到组件有class(类)组件,和函数(无状态)组件,class组件中有自己的生命周期和自己的状态,而函数组件是一个无状态组件,Hook的出现正式为了解决这个问题,Hooks可以让函数式组件可以拥有state,生命周期等特性

二.为什么要使用Hook

Hook解决了我们在组件之间复用状态逻辑很难的缺陷,使我们更加便捷的操作可以复用的状态逻辑,因为是函数式组件,效率上来说肯定是比Class类组件要高的.并且解决了我们使用函数式组件时可以使用更多的 React 特性

三.使用Hook

1.State Hook

1.1 useState()

返回一个state,以及更新state的函数,传递进去的参数决定这你声明了何种数据类型的变量

// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(20);

PS:在初始渲染期间,返回的状态state与传入的第一个参数相同,第二个解构的变量是返回的更新state的函数

1.2 setState()

setState方法由我们自己定义,是解构出来的第二个变量,这是更新state的函数
setCount(count + 1);
它接收一个新的state,并将组件重新渲染,虽然组件重新渲染,但是操作的state,永远是最新的那个state

export default function Hooks(props) {
    //声明一个count变量的state,初始值为数字类型20
    let [count, setCount] = useState(20);
    //声明一个msg变量的state,初始值为字符串的hello hook
    let [msg, setMsg] = useState('hello hook');
    //声明一个list变量的state,初始值为数组类型
    let [list, setList] = useState(['123']);

    //使用useState返回的更新函数
    function Click() {
        setCount(count + 1);
        setMsg(msg + "world");
    };

    console.log(count);
    console.log(msg);
    console.log(list.length);
    return (
        <div>
            <h1>{count}</h1>
            <h1>{msg}</h1>
            <button onClick={Click}>按钮</button>
        </div>
    );
}
1.3 惰性初始 state

在传入的useState初始参数是惰性的,只会在第一次渲染的时候起作用,后面不管怎么渲染,都会被忽略,如果这个初始值是动态的,需要计算获取,可以直接传入一个函数,然后返回这个值

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

2.Effect Hook

Effect Hook 可以让你在函数组件中执行副作用操作
所谓的副作用,包括开启长连接、调接口、DOM操作、定时器等都是属于副作用
PS: useEffect Hook相当于是下面生命周期函数的组合
componentDidMount
componentDidUpdate
componentWillUnmount

2.1 useEffect()

useEffect()的第一个参数,必须是一个函数,并且这个函数的返回值可选,一般返回清除副作用的函数,比如清除定时器,如果不需要清除,可以不返回useEffect()的第二个参数,是一个数组,可选,数组里面表示这个副作用的操作依赖的状态变量

 useEffect(() => {
     //类似componentDidMount()的功能,在组件挂载之后调用
     //可以用于开启定时器,进行调接口,开长连接
     timer = setInterval(() => {
         setCount(count + 1);
     }, 1000);
     return () => {
          //类似componentWillUnmount()的功能,在组件卸载之前调用
          //可以进行关闭定时器,关闭长连接
         clearInterval(timer);
     };
 },
 //类似componentDidUpdate()的功能,在组件更新之后进行调用
 [count]);

PS:
React首次渲染和之后的每次渲染都会调用一遍useEffect函数,而我们使用class组件的时候,必须要用到2个生命周期函数,分别是首次渲染(componentDidMount)和更新导致的渲染(componentDidUpdate)
useEffect中定义的函数的执行不会阻碍浏览器更新视图,因为这个函数是异步执行的,而在
componentDidMount和componentDidUpdate中是同步执行的
可以为 useEffect() 传入第二个参数,它是一个数组,数组里面表示这个副作用的操作依赖的状态变量,换句话说:
如果这个副作用的操作依赖的状态变量没有改变,则不会执行副作用操作。
2.2 使用useEffect的问题
1.为什么要在 effect 中返回一个函数?
这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分
2.React 何时清除 effect
React 会在组件卸载的时候执行清除操作。effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。
3.effect 中的是否必须要返回?
useEffect 可以在组件渲染后实现各种不同的副作用。有些副作用可能需要清除,所以需要返回一个函数,如果不需要清理,就不用返回
4.组件中可以包含多个useEffect
使用多个 Effect 实现关注点分离,也就是说组件中可以多个useEffect进行处理逻辑代码,按照不同的代码业务分离他们

useEffect(() => {
    document.title = "我的";
});
useEffect(() => {
    timer = setInterval(() => {
        setCount(count + 1);
    }, 1000);
    return () => {
        clearInterval(timer);
    };
}, [count]);
1234567891011
5.通过传入useEffect的第二个参数,进行性能优化
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

如果这个副作用的操作依赖的状态变量没有改变,则不会执行副作用操作

3.Hook 规则

1.只在最顶层使用 Hook
不要在循环,条件或嵌套函数中调用 Hook

function Form() {
  // 1. Use the name state variable
  const [name, setName] = useState('Mary');

  // 2. Use an effect for persisting the form
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  // 3. Use the surname state variable
  const [surname, setSurname] = useState('Poppins');

  // 4. Use an effect for updating the title
  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

React
记住:不要在循环体,嵌套函数体以及条件中使用Hook
2.只在 React 函数中调用 Hook
不要在普通的函数中调用Hook但是可以在React的函数组件中调用Hook也可以自定义Hook中调用其他Hook
3.使用ESLint插件强制执行规则
npm install eslint-plugin-react-hooks --save-dev
ESLint配置

// 你的 ESLint 配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
    "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
  }
}

4.useContext()

React 还提供了支持上下文的Hook useContext
在函数式组件中,同样也可以使用上下文(context)

const GlobalContext = useContext(MyContext);

使用方式与class一样,只不过这里声明是使用useContext进行声明,使用方式请参考:上下文(context参考此链接)

5.额外的Hook

5.1 useReducer()

useState的替代方案,在某些场景下,useReducer会比use更实用,比如state逻辑复杂且包含多个子值,或者下一个state依赖之前的state等
使用useReducer还能给那些会触发深更新的组件做性能优化

5.2 useCallback()

用于渲染优化

5.3 useMemo()

用于渲染优化
这两种优化方案,参考简书上大神的文章

5.4 useRef()

5.5 useImperativeHandle()

可以你在使用 ref 时自定义暴露给父组件的实例值

5.6 useLayoutEffect()

与useEffect相同 ,只不过它是同步的.它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
如果使用useEffect出问题了,可以尝试使用这个函数来解决一定的问题但是 尽可能使用标准的useEffect以避免阻塞视觉更新.

5.7 useDebugValue()

useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值