React Hooks用法与实战

本文探讨了React Hooks的诞生原因,包括组件间状态逻辑复用困难、复杂组件难以理解和Class组件的挑战。详细介绍了useState、useEffect、useCallback、useMemo、useRef和useContext等常用Hooks的用法,以及自定义Hooks的应用,如强制渲染、获取滚动条位置和实现虚拟列表。通过实例解析,强调了Hooks在简化代码和提高可维护性方面的重要作用。
摘要由CSDN通过智能技术生成

一、为什么要发明hooks?

1.在组件之间复用状态逻辑很难

在class组件中,我们如果复用状态逻辑,可以使用比如 render props 和 高阶组件。但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解。而hooks可以简单的去实现状态逻辑的复用。

2.复杂组件变得难以理解

class组件的每个生命周期常常包含一些不相关的逻辑,完全不相关的代码却在同一个方法中组合在一起,如此很容易产生 bug,并且导致逻辑不一致。

3.难以理解的 class

class 是学习 React 的一大屏障,还必须去理解 JavaScript 中 this 的工作方式。还不能忘记绑定事件处理器。没有稳定的语法提案,这些代码非常冗余。

二、常用的hook及其用法

1.useState:让函数组件具有维持状态的能力

state(在一个函数组件的多次渲染之间,这个 state 是共享的) 是 React 组件的一个核心机制,useState 这个 Hook 就是用来管理 state 的,下面我分别用hooks组件和class组件来对比一下两种写法。
class组件:

import React from "react";

class Demo extends React.Component {
   
  constructor(props) {
   
    super(props);
    this.state = {
   
      num: 1
    };
  }
  handleAdd = () => {
   
    const newNum = this.state.num + 1;
    this.setState({
    num: newNum });
  };
  render() {
   
    return (
      <div>
        {
   this.state.num}
        <button onClick={
   this.handleAdd}>增加</button>
      </div>
    );
  }
}
export default Demo;

hooks组件:

import React, {
    useState } from "react";
const Demo = () => {
   
  const [num, setNum] = useState(1);
  const handleAdd = () => {
   
    const newNum = num + 1;
    setNum(newNum);
  };
  return (
    <div>
      {
   num}
      <button onClick={
   handleAdd}>增加</button>
    </div>
  );
};
export default Demo;

useState(initialState) 的参数 initialState 是创建 state 的初始值;返回值是一个有着两个元素的数组,第一个元素用来读取 state 的值,第二个则是用来设置这个 state 的值;如果要创建多个 state,那么我们就需要多次调用 useState。

useState 应该算最简单的一个 Hooks,但在使用中,也有很多技巧可循,如果严格按照以下几点,代码可维护性直接翻倍:

重点:
1.能用其他状态计算出来就不用单独声明状态。一个 state 必须不能通过其它 state/props 直接计算出来,否则就不用定义 state。
2.保证数据源唯一。在项目中同一个数据,保证只存储在一个地方。不要既存在 redux 中,又在组件中定义了一个 state 存储;不要既存在父级组件中,又在当前组件中定义了一个 state 存储;不要既存在 url query 中,又在组件中定义了一个 state 存储。
3.useState 适当合并。useState 拆分过细,导致代码中一大片 useState,最终使得项目bug多多难以维护。

2.useEffect:执行副作用(副作用是指一段和当前执行结果无关的代码)

对应到 Class 组件,那么 useEffect 就涵盖了 ComponentDidMount、componentDidUpdatecomponentWillUnmount 三个生命周期方法。

useEffect接收两个参数,第一个为要执行的函数 callback,第二个是可选的依赖项数组 dependencies,其中依赖项是可选的,如果不指定,那么 callback 就会在每次函数组件执行完后都执行;如果指定了,那么只有依赖项中的值发生变化的时候,它才会执行。

1.有依赖项时,只有当依赖项发生变化时才执行。例如:

const [state, setState] = useState(0);
useEffect(() => {
   
  // state改变之后才会执行
  console.log('state-changed');
}, [state]);

2.没有依赖项,则每次 render 后都会重新执行。例如:

useEffect(() => {
   
  // 每次 render 完一定执行
  console.log('re-rendered');
});

3.空数组作为依赖项,则只在首次执行时触发,对应到 Class 组件就是 componentDidMount。例如:

useEffect(() => {
   
  // 组件首次渲染时执行,等价于 class 组件中的 componentDidMount
  console.log('did mount');
}, [])

4.useEffect 还允许你返回一个函数,用于在组件销毁的时候做一些清理的操作,类似于componentWillUnmount,例如:

useEffect(() => {
   
  return () => {
   
    // 组件卸载时执行,等价于 class 组件中的 componentWillUnmount
    clearInterval(timer1);
  }
}, [
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值