Function Component 與 Class Component 有何不一樣?

有段時間,這個問題標準回答是 class 組件提供了訪問更多特性的權限(好比state),隨着 Hooks 發佈,那就不是這樣了。javascript

或許,你聽過他們中哪一個性能更好這樣的問題,性能取決於你的代碼作了什麼而不是你選擇用 function 仍是class 組件。實際上這二者之間的性能差異是微不足道的,具體能夠參考這個對比結果html

在這篇文章中,咱們來看看它們二者之間最大的不一樣。java

function 組件捕獲渲染的值特性(captaure the rendered values)

事先申明:並不對 Function 與 Classes 進行優劣對比,而僅僅是說明 react 兩種模式的不一樣。react

對比下面兩段代碼:git

Function Component:github

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

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

  return <button onClick={handleClick}>Follow</button>;
}複製代碼

Class Component:ide

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 展現的是修改後的值this

class.gif


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

func.gif

這個例子中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 特性。

相關文章
相關標籤/搜索