react hooks 实践总结(一):class component 和 function component

自从深入了解了 react hooks(后面简称 hooks),被其简洁的编写方式和强大的扩展性深深吸引,然后我就迫不及待地想把它应用到实际项目中。

使用下来发现,真香!但是坑也不少,react hooks 使用起来确实简洁不少,甚至说有点黑魔法的味道。这就容易导致不怎么了解 hooks 实现原理和函数组件的渲染过程的人很容易在使用 hooks 编写组件时出现一些很离奇的 bug。

这篇文章主要讨论 react 中 class 组件和函数组件的一些区别,为后续的文章分析在函数组件中使用 hooks 时由于函数式组件的变量作用域造成的 bug 做铺垫。

函数式组件和 class 组件渲染上区别

先来看看测试代码:

import * as React from "react";
import { render } from "react-dom";
const { Component } = React;

interface ClassComponentProps {
  color: string;
}

// class 组件
class ClassComponent extends Component<ClassComponentProps> {
  constructor(props) {
    super(props);
    console.log('create a class component!');
  }

  render() {
    console.log('re-render class component!');
    const { color } = this.props;
    return (
      <div className="class-component" style={{ color: color }}>class component</div>
    );
  }
}

interface FuncComponentProps {
  color: string;
}

const FuncComponent = ({ color }: FuncComponentProps) => {
  console.log('execute the function component!');
  
  return (
    <div className="func-component" style={{ color: color }}>function component</div>
  );
};

function App() {
  const [color, setColor] = React.useState<string>("black");
  const [inputColor, setInputColor] = React.useState<string>('');
  const handleInputChange = (event) => setInputColor(event.target.value);
  const handleSubmit = (event) => setColor(inputColor);
  
  return (
    <div className="App">
      <ClassComponent color={color} />
      <FuncComponent color={color} />
      <input type="text" value={inputColor} onChange={handleInputChange}/>
      <button onClick={handleSubmit}>修改颜色</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);
console.log('Init the App!');
复制代码

上面的代码总共定义了3个组件,一个 class 组件即 ClassComponent,另2个都是函数式组件包括 App 组件。通过输入一个颜色值改变 ClassComponent 和 FuncComponent 组件的文本颜色。

class 组件的整个生命周期就是其实例创建(new)到销毁的过程。

函数式组件在每次渲染时则是直接执行一次其函数式组件这个函数本身

看一下面的测试截图:

从截图可以看出一些信息,项目初始化完成时创建了一个 ClassComponent 组件实例,执行了构造器, render 函数。执行了一次函数式组件 FuncComponent 这个函数。初始化完毕,输出前四句:

create a class component!
re-render class component!
execute the function component!
Init the App!
复制代码

然后在输入blue的过程中由于调用了 setInputColor,并且新的 inputputColor和之前的 color 不一样,所以会重新渲染。重新渲染过程中不会创建新的 ClassComponent 实例,只是执行了先前实例的 render 函数,这样的话,重新渲染的时候在 render 函数中使用的变量是之前就绑定到 ClassComponent 实例上的变量。

而对于函数式组件,只是纯粹的暴力的重新执行 FuncComponent这个函数,渲染它输出的结果,这里我们要注意,因为函数式组件重新渲染只是重新执行函数式组件本身,所以函数式组件是无法保存上次渲染过程中的变量了,也就是无法使用 state。所以在 react hooks API 出来之前,我们使用函数式组件都是在不使用 state 的情况下作为一个无状态的 UI 组件使用(不考虑使用其它工具库,如: mobx)。

react hooks 为 function component 带来state

上面的测试代码中, App 组件也是函数式组件,但是我们看到有了 react hooks 之后,函数式组件也有了 state

写个喜闻乐见的计数器:

import * as React from "react";
import { render } from "react-dom";

function App() {
  const [count, setCount] = React.useState<number>(0);
  const increate = () => setCount(count + 1)
  
  return (
    <div className="App">
      <h3 className="count">{count}</h3>
      <button onClick={increate}>+</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);
复制代码

想想看,换成 class 组件要多好几行代码?。我们来分析一下,我们点击 + 按钮后发生了啥:

点击了 + 按钮触发点击事件,调用 setCount(count + 1),由于新的 count 比原来不一样,导致 App 组件重新渲染,重新执行 App 函数,执行到 const [count, setCount] = React.useState<number>(0) 这一行的时候,我们拿到 count这个变量,同样是通过 useState(0)。我们知道对于 App 函数,第一次初始化和此时的重新渲染,每次函数执行过程中的变量都是重新定义的。为什么这个时候返回的却是更新后的 count 呢?这就有点黑魔法的味道了,为什么第二次执行 use state 拿到的是更新后的 count。其实网上讲 hooks 原理的文章已经有不少了。这里我简单叙述下我当前的理解:

对于 useState 这个 hook。因为我们是可以多次调用 useState 的,所以需要一个数组 stateArray 来保存多个 state。然后还需要一个游标变量 cursor 来保存当前 useState 的次序,默认为 0.

在函数组件初始化时也就是第一次执行函数组件时,每调用一次 useState(initState),就会把 initState保存到stateArray[cursor]。然后将游标 cursor 加一,函数组件执行结束时将游标置 0。

当你在组件的事件回调中 setState(newState) 了,会将 newSatte 直接替换原有的 state。

再次渲染函数组件时,也就是重新执行函数组件,因为游标被置 0,所以从 stateArray可以取到对应的更新后的 state。

除了第一次渲染和 useState(initState) 中的 initState 有关系外,后续的渲染和 initState 都没关系。

关于 react hooks 的第一篇文章就到这里了,下一篇将介绍如何使用 hooks 让函数组件能达到以前只有使用 class 组件才能做到的功能以及 custom hooks。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值