函数式组件与类组件有何不同

简介: React 中最关键的知识点就是 组件,在 React 16.8 之前(还没有 Hooks 前),我们的应用大多写成 Class 组件,因为 Class 组件有生命周期,能控制状态(state)。但函数式组件只能默默站在后面,说自己是木偶组件(也叫无状态组件),传来 props,展示UI

前言



React 中最关键的知识点就是 组件,在 React 16.8 之前(还没有 Hooks 前),我们的应用大多写成 Class 组件,因为 Class 组件有生命周期,能控制状态(state)。但函数式组件只能默默站在后面,说自己是木偶组件(也叫无状态组件),传来 props,展示UI


以下文字都基于有了 Hooks 后


正文



函数式组件和类组件之间是否有什么根本上的区别?


函数式组件捕获渲染时的值


具体可以看这篇文章:函数式组件与类组件有何不同?[1]


因为在 React 中 props 是不可变(immutable)的,它们永远不会改变。然而,this 是可变(mutable)的


事实上,这就是类组件 this 存在的意义。React 本身会随着时间的推移而改变,以便你可以在渲染方法以及生命周期方法中得到最新的实例


函数式组件会捕获当前状态下的值,如果你使用定时器改变当前值的状态,那函数式组件显示的还是原来的值,而不是最新值。而类组件会一直获取最新值


只要一渲染,函数式组件就会捕获当前的值。而类组件即使渲染了,但是它的 this 会指向最新的实例


类组件



可以看线上Demo[2]


class ClassDemo extends React.Component {
  state = {
    value: ""
  };
  showMessage = () => {
    alert("最新值为 " + this.state.value);
  };
  handleMessageChange = (e) => {
    this.setState({ value: e.target.value });
  };
  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };
  render() {
    return (
      <div>
        <input value={this.state.value} onChange={this.handleMessageChange} />
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}


这样的结果是点击后获取到最新的值,而不是 3 秒前的值。为什么?因为 this 可变,3 秒之后执行 alert("最新值为 " + this.state.value)。this.state.value 指向最新的值


如果类组件如果想保存原来的值该怎么做?


一、调用事件之前读取this.props


可以看线上Demo[3]


showMessage = (value) => {
    alert("最新值为 " + value);
};
handleClick = () => {
    const { value } = this.state;
    setTimeout(() => this.showMessage(value), 3000);
};


可以解决,但点击时获取到当前的 user,再传递给 this.showMessage,这样,即使 3 秒之后也是原来的值


缺点:每次都要从 this.props 中拿值,如果数据一多,写起来不符合人性


二、在构造函数中绑定方法


可以看线上Demo[4]


constructor(props) {
    super(props);
    this.showMessage = this.showMessage.bind(this);
    this.handleClick = this.handleClick.bind(this);
}


这个方法解决不了问题。我们的问题是我们从 this.props 中读取数据太迟了—— 读取时已经不是我们所需要使用的上下文


三、利用闭包


把方法写进 render 中,这样每次渲染时就能捕获住当时所用的 props 或者 state

可以看线上Demo[5]


class ClassDemo extends React.Component {
  state = {
    value: ""
  };
  render() {
    const { value } = this.state;
    const showMessage = () => {
      alert("最新值为 " + value);
    };
    const handleMessageChange = (e) => {
      this.setState({ value: e.target.value });
    };
    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };
    return (
      <div>
        <input value={this.state.value} onChange={handleMessageChange} />
        <button onClick={handleClick}>点击</button>
      </div>
    );
  }
}


但是这个方法很蠢,这个写法和函数式组件有什么区别呢?还不如用函数式组件呢


函数式组件如果想保存最新的值呢


使用 useRef 保存最新的值,让组件获得最新的值


function MyComponent() {
  const ref = useRef(null);
}


首先,ref 与实例都扮演同样的角色[6],ref 对象是一个有 current 属性的一个容器

上次的例子我们用函数式组件就可以这样写:


const FunctionDemo = () => {
  const [value, setValue] = useState("");
  const refValue = useRef("");
  const showMessage = () => {
    alert("最新值为 " + refValue.current);
  };
  const handleMessageChange = (e) => {
    setValue(e.target.value);
    refValue.current = e.target.value;
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <div>
      <input value={value} onChange={handleMessageChange} />
      <button onClick={handleClick}>点击</button>
    </div>
  );
};


可以看线上Demo[7]


这里笔者提出两个疑问:


  • 为什么 ref 能保存住最新的值?


  • 为什么函数式组件会捕获,类组件不会呢?


后续文章会给出笔者的回答


参考资料



[1] 函数式组件与类组件有何不同?: https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/


[2] 线上Demo: https://codesandbox.io/s/function-components-different-from-classes-2dligb?file=/src/ClassDemo.js:0-551


[3] 线上Demo: https://codesandbox.io/s/function-components-different-from-classes-2dligb?file=/src/ClassDemo2.js:0-592


[4] 线上Demo: https://codesandbox.io/s/function-components-different-from-classes-2dligb?file=/src/ClassDemo3.js


[5] 线上Demo: https://codesandbox.io/s/function-components-different-from-classes-2dligb?file=/src/ClassDemo4.js:104-565


[6] 扮演同样的角色: https://zh-hans.reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables


[7] 线上Demo: https://codesandbox.io/s/function-components-different-from-classes-2dligb?file=/src/FunctionDemo2.js


[8] 函数式组件与类组件有何不同?: https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/



相关文章
|
7月前
|
存储 前端开发 JavaScript
【第29期】一文学会用React类组件编写组件
【第29期】一文学会用React类组件编写组件
78 0
|
2月前
|
前端开发 开发者
React 函数组件与类组件对比
【10月更文挑战第4天】本文详细比较了React中的函数组件与类组件。函数组件是一种简单的组件形式,以纯函数的形式返回JSX,易于理解与维护,适用于简单的UI逻辑。类组件则是基于ES6类实现的,需要重写`render`方法并能利用更多生命周期方法进行状态管理。文章通过示例代码展示了两者在状态管理与生命周期管理上的差异,并讨论了常见的问题如状态更新异步性与生命周期管理的复杂性,最后给出了相应的解决方法。通过学习,开发者可以根据具体需求选择合适的组件类型。
63 8
|
29天前
|
前端开发
如何定义和使用React泛型组件
通过合理地定义和使用React泛型组件,可以提高代码的复用性和可维护性,同时增强类型安全性,使React应用程序的开发更加高效和可靠。
47 8
|
4月前
|
前端开发 JavaScript
React 中的函数组件和类组件
【8月更文挑战第31天】
67 0
|
7月前
|
前端开发 JavaScript 开发者
React的函数组件与类组件:探索两者之间的区别
【4月更文挑战第25天】React提供函数组件和类组件,两者在语法、状态管理、生命周期和性能优化上有所不同。函数组件简单且易于理解,使用 Hooks 可添加状态管理;类组件支持复杂状态管理和生命周期方法,适用于需要精细控制更新的场景。随着 Hooks 的发展,函数组件功能增强,成为更多开发者的首选。选择组件类型应根据实际需求权衡。
|
7月前
|
存储 前端开发 JavaScript
探索React中的类组件和函数组件
探索React中的类组件和函数组件
|
前端开发
React中的类组件和函数组件之间有什么区别?
相同点 1、组件名首字母必须大写 2、返回的组件只能有一个根元素 3、都不能修改props
|
前端开发 JavaScript C++
React 类组件和函数组件
React 类组件和函数组件
184 0
|
7月前
|
前端开发
React中函数组件与类组件的两种使用
React中函数组件与类组件的两种使用
|
7月前
|
前端开发 JavaScript
react的类组件和函数式组件有什么区别
react的类组件和函数式组件有什么区别
182 0