Function Component 与 Class Component 有何不同?

有段时间,这个问题标准回答是 class 组件提供了访问更多特性的权限(比如state),随着 Hooks 发布,那就不是这样了。

或许,你听过他们中哪个性能更好这样的问题,性能取决于你的代码做了什么而不是你选择用 function 还是class 组件。实际上这两者之间的性能差别是微不足道的,具体可以参考这个对比结果

在这篇文章中,我们来看看它们两者之间最大的不同。

function 组件捕获渲染的值特性(captaure the rendered values)

事先申明:并不对 Function 与 Classes 进行优劣对比,而仅仅是说明 react 两种模式的不同。

对比下面两段代码:

Function Component:

function ProfilePage(props) {
  const showMessage = () => {
    alert("Followed " + props.user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return <button onClick={handleClick}>Follow</button>;
}复制代码

Class Component:

class ProfilePage extends React.Component {
  showMessage = () => {
    alert("Followed " + this.props.user);
  };

  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };

  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }复制代码

这两个组件代码都描述了同一个逻辑:点击按钮 3 秒后 alert 父级传入的用户名。通过这个 在线 Demo 完整代码,执行以下操作来说明两者的区别:

  1. 点击follow 按钮
  2. 在3秒弹窗之前,选择profile select
  3. 观察alert 弹出的值是什么

我们可以看到:

Class Component 展示的是修改后的值


Function Component 展示的是修改前的值:

这个例子中function 组件展示的才是我们期望的结果,因为我点了 follow 不希望因父级 props变化而改变原本期望的渲染结果,为什么 class 组件例子中出现这种情况?

class ProfilePage extends React.Component {
  showMessage = () => {
    alert("Followed " + this.props.user);
  };复制代码

原因是在 react 中 props 不可变(Immutable) 数据,但是在 react class 组件中,this 是可变的,因此 this.props 的调用会导致每次都访问最新的 props。上面的 showMessage 是在3秒后执行,这时props是最新的。而 Function Component 不存在 this.props 的语法,因此 props 总是不可变的。

如何解决这个问题?

一种方式是在事件绑定方法中读取这个 props ,然后传递给showMessage:

class ProfilePage extends React.Component {
  showMessage = (user) => {
    alert('Followed ' + user);
  };

  handleClick = () => {
    const {user} = this.props;
    setTimeout(() => this.showMessage(user), 3000);
  };

  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }
}复制代码

但是这样写代码显得臃肿啰嗦,而且,如果在showMessage中要调用其他方法,这个方法又要读取 this.props.somthing 或者 this.state.someting 又要传递this.props 或者 this.state,这样就很麻烦。

另一种方式就是在 render 函数中读取props:

class ProfilePage extends React.Component {
  render() {
    // Capture the props!
    const props = this.props;

    // Note: we are *inside render*.
    // These aren't class methods.
    const showMessage = () => {
      alert('Followed ' + props.user);
    };

    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };

    return <button onClick={handleClick}>Follow</button>;
  }
}复制代码

这看起来很奇怪,加以简化,其实就是 function 组件。

Hooks 也具有 capture rendered values 特性

看下面代码:

function MessageThread() {
  const [message, setMessage] = useState('');

  const showMessage = () => {
    alert('You said: ' + message);
  };

  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };

  return (
    <>
      <input value={message} onChange={handleMessageChange} />
      <button onClick={handleSendClick}>Send</button>
    </>
  );
}复制代码

在点击 Send 按钮后,再次修改输入框的值,3 秒后的输出依然是 点击前输入框的值。这说明 Hooks 同样具有 capture value 的特性。

如果我们想避开 capture values 的特性,就想获取最新的输入框的值怎么办?在 class 组件中,我们只需要访问 this.props 就行,因为 this 是可变的,能读取最新的props。

这里我们利用 useRef 可以规避 capture values 特性:

function MessageThread() {
  const [message, setMessage] = useState('');

  // Keep track of the latest value.
  const latestMessage = useRef('');
  useEffect(() => {
    latestMessage.current = message;
  });

  const showMessage = () => {
    alert('You said: ' + latestMessage.current);
  };

  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };

  return (
    <>
      <input value={message} onChange={handleMessageChange} />
      <button onClick={handleSendClick}>Send</button>
    </>
  );
}复制代码

总结:

function 组件与 class 组件最大的不同是 function 组件能够捕获渲染的值,而 class 组件因为 react 中 this 是可变的,所以总是能获取最新的 props 。同样 hooks 和 function 组件一样具有 capture values 特性,利用useRef 可以避免 capture values 特性。


转载于:https://juejin.im/post/5cc190056fb9a0324a08afcd

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值